Lieber Leser
Herzlich Willkommen und vielen Dank, dass Sie sich für Yana entschieden haben.
In diesem Programm stecken mehrere Jahre mühevoller Entwicklungsarbeit, sowie viele Stunden, welche unzählige helfende Hände investiert haben, um durch Tipps, Vorschläge und Programmtests dieses Programm stetig zu verbessern.
Alle diese Stunden haben mir und allen, die an diesem Projekt beteiligt waren, sehr viel Freude bereitet.
Wir hoffen, dass Ihnen das Ergebnis unserer Arbeit gefällt. Bitte berichten Sie uns von Ihren Erfahrungen. Falls Sie Vorschläge haben stehe ich Ihnen gern via E-Mail zur Verfügung.
Thomas Meyer
Yana ist ein unternehmenstaugliches Framework für PHP mit dem Ziel, Ihren gesamten Entwicklungsprozess zu unterstützten - statt nur MVC zu liefern.
Diese Software ist eine Entwicklungsplattform für Webanwendungen in PHP, AJAX und SQL.
Sie bietet Rapid-Prototyping für einen einfachen, schnellen Start. Entwickler können auf einem simulierten Datenbankserver arbeiten, der automatisch die Datenbank aktualisiert, während sie arbeiten. Um live zu gehen, ist ein Deployment der Datenbank auf einem echten DBS jederzeit möglich. Ihre Webformulare und PHP-Code passen sich automatisch an Datenbankänderungen an. Die Software unterstützt mehrere DBMS - nicht nur MySQL. Sie bietet eine erweiterte Smarty Template-Engine mit Unterstützung für Skins. Professionelle Übersetzter erhalten Unterstützung durch automatisch erzeugte Sprachdateien nach OASIS XLIFF Standard. Entwickler finden eine flexible Pluginarchitektur, um hochgradig variable Softwareprodukte mit vielen Produktvarianten zu erstellen. Die Wartung unterstützen wir durch eingebaute Selbstdiagnose und eine hohe Testabdeckung. Ein grafische Installer ist in Vorbereitung, um Sie in der Deploymentphase durch den Installationsprozess zu führen.
Yana ist leicht zu erlernen und gut dokumentiert. Videotutorials and ein umfassendes Handbuch mit zahlreichen Abbildungen und Screenshots unterstützen Sie auf Ihren ersten Schritten.
Damit dieses Programm korrekt arbeitet, müssen folgende Mindestanforderungen erfüllt sein:
Folgende Konfiguration wird empfohlen:
In diesem Abschnitt finden Sie Hinweise auf Eigenheiten bestimmter Systemkonfigurationen, sowie Informationen zu typischen Konfigurationsfehlern und Ratschläge, die Ihnen helfen können, falls während der Installation Probleme auftreten.
1 | index.php | Startseite |
2 | library.php | lädt Systembibliotheken |
3 | cli.php | Kommandozeilenprogramm für Cron-Jobs |
4 | cache/ | Verzeichnis für temporäre Dateien und Log-Files |
5 | common_files/smilies/ | hier können neue Emoticons eingefügt werden |
6 | config/ | Konfigurationsdateien |
7 | includes/ | Yana Kernsystem |
8 | languages/ | Übersetzer können hier neue Sprachdateien hinzufügen |
9 | libs/ | weitere Bibliotheken |
10 | plugins/ | PHP-Programmierer können hier eigene Erweiterungen der Anwendung speichern |
11 | skins/ | Webdesigner können hier zusätzliche Skins und Layouts für die Anwendung speichern |
12 | config/db/ | Datenbanken und Konfigurationsdateien |
13 | config/profiles/ | Einstellungen des Administrationsmenüs |
14 | config/dbconfig.php | Parameter der Datenbankverbindung |
16 | config/system.config.xml | Systemkonfiguration |
16 | config/system.drive.xml | Pfadangaben zu Systemdateien |
Hinweis zu Lizenzen:
Das Installationspaket enthält Komponenten unterschiedlicher
Hersteller.
"Yana Framework für PHP" von Thomas Meyer
Diese Software steht unter der GNU
GPL.
Deren Lizenzbedingungen können Sie hier ( gpl.txt
) einsehen.
"Handbuch zum Yana Framework" von Thomas Meyer
Dieses Handbuch steht unter der Creative Commons Attribution-Licence 3.0.
Deren Lizenzbedingungen können Sie hier (
creativecommons.org/licenses/by/3.0
) einsehen.
"Smarty Template-Engine" von New Digital
Group
Diese Software steht unter der GNU
LGPL.
Deren Lizenzbedingungen können Sie hier ( lgpl.txt
) einsehen.
"PhpConcept Library - Zip Module" von
Vincent Blavet
Diese Software steht unter der GNU
LGPL.
Deren Lizenzbedingungen können Sie hier ( lgpl.txt
) einsehen.
"The DHTML Calendar" von Mihai Bazon
Diese Software steht unter der GNU
LGPL.
Deren Lizenzbedingungen können Sie hier ( lgpl.txt
) einsehen.
"Tiny MCE"
Diese Software steht unter der GNU
LGPL.
Deren Lizenzbedingungen können Sie hier ( lgpl.txt
) einsehen.
"SQL-Parser" von
Brent Cook
Diese Software steht unter der GNU
LGPL.
Deren Lizenzbedingungen können Sie hier ( lgpl.txt
) einsehen.
"JQuery" von John Resig
Diese Software steht unter der MIT-Lizenz.
Deren Lizenzbedingungen können Sie hier ( mit.txt
) einsehen.
"Interactive Photo Desk" von Mary Lou
Diese Software steht unter der MIT-Lizenz.
Deren Lizenzbedingungen können Sie hier ( mit.txt
) einsehen.
Als Gerichtsstand gilt der Wohnort des Autors.
Sie benutzen diese Software und die beiliegende Dokumentation auf eigene Gefahr. Für jegliche Schäden, welche in Folge der Benutzung dieser Software entstehen könnten übernimmt der Autor keinerlei Haftung.
Sie sind herzlich eingeladen, Übersetzungen, Skins oder Quellcode beizutragen. Schreiben Sie einfach eine Mail. Für Fragen steht Ihnen das Forum jederzeit offen.
Sollten Sie nicht die Möglichkeit haben sich direkt zu beteiligen, sind Spenden stets gern gesehen.
Ansprechpartner: | Thomas Meyer |
---|---|
Projektwebsite: | www.yanaframework.net |
Mail für Fragen: | ![]() |
Beachten Sie bitte die Systemvoraussetzungen und Kompatibilitätshinweise.
Sobald Sie das Installationsprogramm gestartet haben sollten Sie folgende Seite sehen:
Zum Fortfahren klicken Sie auf die Schaltfläche "weiter".
Um mit der Installation fortzufahren, müssen Sie die Lizenzbedingungen akzeptieren. Andernfalls, können Sie die Installation mit der unteren Schaltfläche abbrechen.
Klicken Sie auf die Schaltfläche "Installation jetzt starten". Klicken Sie anschließend auf "weiter".
Mit diesem Passwort können Sie das Administrationsmenü der Anwendung aufrufen. Verwenden Sie dazu den Login "Administrator". Das Passwort geben Sie bitte erst in das linke Feld ein und wiederholen das im rechten Feld. Klicken Sie anschließend auf "OK".
Es wird angezeigt, ob die Operation erfolgreich war oder nicht. Klicken Sie anschließend auf "weiter.
Um sicher zu gehen, dass die Installation erfolgreich war, können Sie eine Selbstdiagnose des Programms durchführen lassen. Klicken Sie dazu auf die Schaltfläche "OK".
Wenn Sie mit der Installation zufrieden sind, klicken Sie auf "weiter".
Nach Beendigung der Installation löscht das Programm selbstständig alle erzeugten temporären Dateien. Wenn Sie die Option "Anwendung jetzt starten" markieren, wird anschließend automatisch das YANA Framework aufgerufen.
Um die Installation zu beenden klicken Sie auf "Fertigstellen".
Beachten Sie bitte die Systemvoraussetzungen und Kompatibilitätshinweise.
Beispiel: Festlegen der Zugriffsrechte
Wenn Sie ein anderes FTP-Programm verwenden, setzen Sie die
Rechte über den FTP-Befehl CHMOD 777
.
Oder versuchen Sie es über die Onlinehilfe Ihres Programms unter dem Stichwort "CHMOD".
Die Installation erfolgt in mehreren Schritten:
Die wichtigsten Schritte zur Konfiguration der Anwendung:
Öffnen Sie in Ihrem Browser die Datei
"index.php?action=index" im Verzeichnis des Programms.
Sie werden aufgefordert, sich am System anzumelden und einen Login,
sowie das dazu gehörige Passwort einzugeben.
(siehe Abbildung)
Geben Sie als "Login" den Text "Administrator" ein.
Falls Sie während der Installation bereits ein Passwort festgelegt haben, müssen Sie dieses nun eingeben.
Sollten Sie das Passwort vergessen haben, lesen Sie bitte im Abschnitt "häufig gestellte Fragen"
weiter.
Bestätigen Sie Ihre Eingabe mit Klick auf "OK". Achten Sie bitte darauf, dass JavaScript in Ihrem Browser aktiviert sein sollte, damit die folgende Seite korrekt dargestellt werden kann.
Tipp: Um zu
verhindern, dass jemand Ihr Passwort erraten kann, sollte es mindestens
eine Länge von 8 Zeichen haben und mindestens 2 Sonderzeichen
enthalten. Leicht zu erraten sind zum Beispiel Geburtstage, Namen von
Personen oder Tieren und Begriffe, welche in handelsüblichen
Wörterbüchern zu finden sind.
Notieren Sie sich Ihr neues Passwort und heben Sie es gut auf.
Fehlermeldung?
Wenn die
Zugriffsrechte nicht gesetzt wurden, wie bei der "Installation"
beschrieben, wird an dieser Stelle eine Fehlermeldung angezeigt. Lesen
Sie in diesem Fall noch einmal nach, was Sie tun müssen und folgen Sie der Anleitung.
Das Administrationsmenü bietet einen Anfänger- und einen Expertenmodus. Einige Optionen sind nur im Expertenmodus sichtbar. Um vom Anfänger- in den Expertenmodus zu wechseln, klicken Sie auf den Link "zu Expertenmodus wechseln".
Abbildung: Position des Links zum Umschalten des Betriebsmodus
Abbildung: Optionen des Administrationsmenüs im Anfängermodus
Hinweis: Installierte Plugins können nur im Expertenmodus aktiviert oder deaktiviert werden.
Abbildung: Optionen des Administrationsmenüs im Expertenmodus
Das Programm verfügt über eine Profilverwaltung, welche es gestattet, mehrere Sätze von Einstellungen (Profile) gleichzeitig zu betreiben. Verwenden Sie dies, um mehrere Layouts/Webseiten/Abteilungen/Fillialen mit der gleichen Installation und verschiedenen Einstellungen zu betreiben.
Beispiel: Dieses Programm kann beliebig vielen Nutzern gleichzeitig jeweils eigene Instanzen der Anwendung zur Verfügung stellen. Bspw. um jedem Nutzer ein eigenes Gästebuch zuzuordnen. Damit diese unterschieden werden können, hat jede Instanz eine ID welche sie eindeutig identifiziert. Diese Id finden Sie auch in der URL des Browsers, als optionalen Parameter "id".
Über die Option "neues Profil anlegen" können Sie neue Profile erzeugen. Um neue Profile erzeugen zu können, müssen Sie über Administratorrechte verfügen.
Falls ein Profil aufgerufen wird, dass noch nicht existiert, werden wahlweise Defaultwerte verwendet, oder ein Fehler gemeldet. Dies ist abhängig von der Einstellung "Community-Freigabe" welche Sie im Menü "Programmsetup" finden. Die Defaultwerte sind im Profil mit dem Namen "Basiseinstellungen" gespeichert.
Um das Profil "Basiseinstellung" (oder ein anderes) zu öffnen, klicken Sie auf "Profil wechseln". (siehe Abbildung)
Die Basiseinstellungen gelten automatisch für alle aufgerufenen Profile, sofern keine anderen Einstellungen festgelegt sind. Außerdem gelten Sie für alle neu angelegten Profile. Achtung: einige Plugins können Optionen besitzen, die entweder NUR, oder aber überall AUSSER in den Basiseinstellungen abgerufen werden können.
Bitte prüfen Sie zunächst, ob Ihre Verbindungsparameter korrekt sind und der Datenbankserver erreichbar ist. Beachten Sie auch die Kompatibilitätshinweise, da sich darunter Informationen und Lösungshinweise zu typischen Schwierigkeiten mit einigen DBMS befinden.
Sollten die Verbindungsparameter korrekt sein und auch kein Problem mit dem Datenbanktreiber oder ein Versionskonflikt vorliegen, können Sie das Problem durch eine manuelle Installation umgehen. Lesen Sie dazu die Anleitung für den Fehlerfall.
Beachten Sie, dass PEAR, PEAR MDB2 und der passende MDB2-Datenbanktreiber, sowie der Datenbanktreiber für PHP installiert sein müssen, um eine Verbindung herstellen zu können.
Administratoren gehen wie folgt vor um ein neues Passwort festzulegen:
Abbildung: Menü "Nutzerübersicht"
Abbildung: Liste aller Nutzer
Abbildung: neues Passwort generieren
Falls Sie Ihr eigenes Passwort vergessen haben, wenden Sie sich an einen anderen Administrator. Falls Sie selbst der Administrator sind, dann kann kein neues Passwort generiert werden. Sie haben aber die Möglichkeit das alte Passwort von Hand zu löschen.
Falls die Installation mit Textdateien arbeitet, verbinden Sie sich bitte via FTP mit Ihrem Konto und laden Sie die Datei "config/db/user/user.sml" herunter. Editieren Sie diese Datei und ersetzen Sie das Passwort durch den Text "UNINITIALIZED". Laden Sie die Datei dann wieder hoch und setzen Sie die Zugriffsrechte mit CHMOD 777.
Falls die Installation mit
einer Datenbank arbeitet,
verbinden Sie sich mit Hilfe eines geeigneten Programms (zum Beispiel
PHPmyAdmin für MySQL) mit der Datenbank und editieren Sie die Tabelle
"user" und setzen Sie für den Nutzer "ADMINISTRATOR" das Passwort auf
"UNINITIALIZED".
Alternativ können Sie auch einfach folgende SQL-Anweisung ausführen.
UPDATE `user` SET user_pwd = 'UNINITIALIZED' WHERE user_id
= 'ADMINISTRATOR';
(Quotes bitte für das von Ihnen verwendete DBMS anpassen)
Denken Sie bitte daran, anschließend ein neues Passwort festzulegen.
Hinweis:
Das echte Passwort wird von diesem Skript niemals als reiner Text
gespeichert. Nach der Eingabe wird es stattdessen verschlüsselt. Diese
Verschlüsselung funktioniert nur in eine Richtung und ist nicht
umkehrbar. Aus diesem Grund ist es nicht möglich, einem Nutzer das von
ihm vergessene Passwort zu nennen, sondern es muss stets ein neues
erstellt werden.
Suchen Sie die Smilies aus, welche Sie einfügen möchten. Achten Sie bitte darauf, dass diese Grafiken im GIF-Format gespeichert sind.
Kopieren Sie anschließend diese
Dateien in das Verzeichnis " common_files/smilies
" des Frameworks.
Wenn Sie die Smilies von einem anderen Verzeichnis als dem vorgegebenen laden wollen, gehen Sie wie folgt vor.
Sollten Sie mehrere Profile verwenden, müssen Sie evtl. die Einstellungen für alle weiteren Profile ebenfalls editieren.
Lesen Sie den Abschnitt " Installation für Anfänger ". Das Programm verfügt ab Version 2.2 über einen Selbstdiagnosemodus. Falls Sie die Installation wie in der Anleitung beschrieben durchgeführt haben, können Sie damit prüfen, ob alle Dateien korrekt installiert sind.
Um den Selbstdiagnosemodus zu starten, rufen Sie in Ihrem Browser das Programm mit der URL "index.php?action=test" auf. Das Programm wird dann damit beginnen, ein Diagnoseprotokoll zu erstellen. Der Selbstdiagnosemodus testet dabei Verzeichnisse und wichtige Dateien und meldet Fehler. Diese werden als rot markierte Zeilen im Protokoll dargestellt. Falls ein Fehler gefunden wird, lesen Sie die Fehlermeldung und befolgen Sie die Anweisungen.
Der
Selbstdiagnosemodus findet einige der typischen Installationsfehler,
kann aber selbstverständlich nicht alle möglichen Fehler finden. Falls
Sie das Programm nach Anleitung installiert haben und trotzdem Probleme
haben es in Betrieb zu nehmen, senden Sie mir am besten eine Mail an . Vergessen Sie nicht die URL anzugeben und
eine Beschreibung Ihres Problems. Dieses Angebot ist für registrierte
Nutzer kostenlos.
Das Datenbank-Setup bietet eine Option "Präfix der Datenbank" (siehe Abbildung). Diese Option IST EXPERIMENTELL und dient ausschließlich dem Zweck, zwei Installationen des YANA Framework auf dem gleichen Server und der gleichen Datenbank arbeiten zu lassen, ohne dass diese sich gegenseitig beeinflussen. In allen Situationen, wo sie nicht benötigt wird, wird wegen ihres experimentellen Status dringend empfohlen, diese Option NICHT zu verwenden.
Abbildung: experimentelle Option zum Setzen eines Präfixes für die
Datenbankverbindung
Eine typische Anwendung für diese Option wäre, dass Sie von einer älteren auf eine neue Version umsteigen möchten und deshalb vorübergehend zu Testzwecken zwei Installationen betreiben möchten, um die neue Version im realen Umfeld zu testen, bevor Sie umsteigen.
Falls Sie ein Präfix angeben, bedeutet dies auch, dass Sie die SQL-Installationsdateien im Verzeichnis "config/db/.install" von Hand so korrigieren müssen, dass die Tabellen entsprechend des von Ihnen gewählten Präfixes benannt sind. Erst danach können Sie die Datenbank wie gewohnt installieren. Für diese Änderung steht zur Zeit noch keine automatische Behandlung zur Verfügung. Den PHP-Quellcode müssen Sie jedoch nicht ändern.
Falls Sie von Ihnen selbst geschriebene Plugins mit handgeschriebenen SQL-Anweisungen verwenden, müssen Sie selbstverständlich auch dort den Quellcode so anpassen, dass die veränderte Benennung der Tabellen berücksichtigt wird. Sollten Sie jedoch die Datenbank-API des Frameworks verwenden und sich Ihre SQL-Anweisungen automatisch erzeugen lassen, dann ist das Editieren der Dateien nicht notwendig. Das Framework passt Ihr SQL zur Laufzeit automatisch an.
Für die Umstellung der SQL-Installationsdateien sollten Sie 5 bis 15 Minuten einplanen.
Falls Sie diese Option versehentlich
verwendet und Probleme mit dem
Zugriff auf Ihre Daten haben sollten, dann können Sie die Einstellung
von Hand zurücksetzen. Editieren Sie dazu bitte die Datei
"config/dbconfig.php" und ändern Sie den Eintrag in Zeile 9 zu:
define('YANA_DATABASE_PREFIX',"");
Anmerkung: in einigen Versionen der Anwendung ist dieses Feature absichtlich deaktiviert.
Falls Sie nicht die Sitemap als Startseite der Anwendung verwenden möchten, ist es möglich diese durch eine andere Seite zu ersetzen - beispielsweise die Startseite eines Plugins Ihrer Wahl.
Öffnen Sie dazu die Datei "config/system.config.xml" in einem Texteditor Ihrer Wahl und ändern Sie den Eintrag "DEFAULT.HOMEPAGE" entsprechend Ihren Wünschen ab (siehe Abbildung).
Falls Sie keine HTML-Eingabe erlauben wollen, haben Sie die Möglichkeit auf EmbTags zur Formatierung von Einträgen zurückzugreifen.
Icon | Tags | Beschreibung | Beispiel | Ausgabe |
---|---|---|---|---|
![]() |
[b] | Text fett formatieren | [b]fetter Text[/b] | fetter Text |
![]() |
[i] | Text kursiv formatieren | [i]kursiver Text[/i] | kursiver Text |
![]() |
[u] | Text unterstreichen | [u]unterstrichener Text[/u] | unterstrichener Text |
![]() |
[code] | Quellcodes einfügen (Code wird nicht ausgeführt, sondern als Text formatiert) |
[code]Text[/code] | Text
|
![]() |
[php] | PHP-Quellcodes einfügen (Code wird nicht ausgeführt, sondern als Text formatiert) |
[php]print 'Hallo Welt';[/php] |
<?php print 'Hallo Welt'; ?> |
![]() |
[color] | legt die Textfarbe fest | [color=red]Text[/color] | Text |
![]() |
[mark] | legt die Hintergrundfarbe fest (Textmarker) | [mark=yellow]Text[/mark] | Text |
![]() |
[url] | Hyperlink einfügen | [url]www.yanaframework.net[/url] | www.yanaframework.net |
![]() |
[mail] | Mailadressen einfügen | [mail]mail@domain.tld[/mail] | mail@domain.tld |
![]() |
[img] | Grafiken einfügen * | [img]domain.tld/img/image.gif[/img] | ![]() |
![]() |
[emp] | Text hervorheben | [emp]Text[/emp] | Text |
![]() |
[h] | Überschrift einfügen | [h]Überschrift[/h] |
Überschrift
|
![]() |
[small] | reduziert die Schriftgröße | [small]kleiner Text[/small] | kleiner Text |
![]() |
[big] | erhöht die Schriftgröße | [big]großer Text[/big] | großer Text |
![]() |
[c] | fügt einen Kommentar ein (zum Beispiel zum Schreiben von Signaturen) |
[c]Kommentar[/c] |
Kommentar
|
![]() |
[hide] | verbirgt einen Text, bis der Nutzer mit der Maus darüber fährt | [hide]das ist ein Geheimnis[/hide] |
das
ist ein Geheimnis
|
![]() |
[wbr] | erlaubt Zeilenumbruch innerhalb eines Wortes | Schiff[wbr]fahrts[wbr]angestellte | Schifffahrts angestellte |
![]() |
[br] | erzwingt Zeilenumbruch | Schiff[br]fahrts[br]angestellte | Schiff fahrts angestellte |
Codebeispiele
Um eine Symbolleiste einzublenden: {%embeddedTags%}Um Embedded-Tags in HTML zu konvertieren: {%$text|embeddedTags%}
*
YANA unterbindet Angriffe auf Ihre Website durch Cross-Site-Scripting
(XSS), weil es nur das Einbinden von Grafiken gestattet, die auf dem
lokalen Server im Verzeichnis des Frameworks liegen. Die Datei muss
außerdem eine der Dateiendungen "jpeg","jpg","png", oder "gif"
besitzen. Sonderzeichen sind nicht gestattet; dadurch wird verhindert,
dass ein Angreifer die wahre URL einer Datei durch den geschickten
Einsatz von Escapesequenzen verschleiern kann, um sich so am Schutz des
Frameworks vorbei zu schmuggeln.
Der Tag [img] ist sinnvoll für Community-Websites, die Ihren Nutzern
den Upload eigener Grafikdateien auf den Server gestatten.
Warnung:
Fehlerhafte Einstellungen können unter Umständen dazu führen, dass das
Programm nicht mehr korrekt ausgeführt werden kann. Führen Sie
derartige Änderungen daher niemals direkt an einem Produktivsystem
durch, sondern prüfen Sie Ihre Einstellungen unbedingt zuvor in einer
Testumgebung.
Es ist möglich, für jedes Website-Profil individuelle Tags festzulegen. Dazu gehen Sie wie folgt vor.
<PROFILE>
...
<EMBTAG>
<tagname>
<TITLE>Wert des Attributes "title"</TITLE>
<TEXT>Benennung</TEXT>
<IMAGE>Bild der Schaltfläche, welche den Tag einfügt</IMAGE>
<1>optionaler regulärer Ausdruck zum Umwandeln in HTML</1>
(Defaultwert = /\[$tagname\](.*)(?:\[\/$tagname\]|$)/Us)
<2>optionaler Ersatzstring zum Umwandeln in HTML</2>
(Default = <span class="embtag_tag_{tagname}">$1</span>)
</tagname>
</EMBTAG>
</PROFILE>
<PROFILE>
...
<EMBTAG>
<bold>
<TITLE>Einfügen von fett formatiertem Text</TITLE>
<TEXT>fetter Text</TEXT>
<IMAGE>%SKINDIR%/default/styles/tags/b.gif</IMAGE>
<1>/\[bold\](.*)\[\/bold\]/Us</1>
<2><b>$1</b></2>
</bold>
</EMBTAG>
</PROFILE>
Hinweis: Wenn
Sie einen Tag entfernen, so wird der Tag nicht mehr als HTML
dargestellt. Dies betrifft auch solche Daten, welche diesen Tag bereits
früher enthalten haben. Beachten Sie auch, dass Sie die Originaltags
nicht entfernen oder ersetzen können.
Melden Sie sich mit Ihrer Frage im Internetforum unter yanaframework.net/forum.
Ein "Skin" ist ein Paket von angepassten Musterseiten und Grafiken. Dieses Paket ändert die Eingabeoberfläche - also das "Look & Feel" Ihrer Anwendung.
Die Änderungen werden beim nächsten Aufruf des Programms aktiv. Sollte der Skin unerwartet nicht aktualisiert werden, leeren Sie im Administrationsmenü den Server-Cache und versuchen Sie es erneut.
Tipps zur Fehlerbehebung
Plugins erweitern Ihre Anwendung um neue Funktionen.
Um das Plugin später wieder zu deaktivieren, wiederholen Sie die Prozedur und entfernen den Haken von der Checkbox links neben dem Namen des Plugins.
Tipps zur Fehlerbehebung
Sprachpakete enthalten Übersetzungen der Textmeldungen der Anwendung in verschiedene Sprachen. Beispielsweise Deutsch oder Englisch.
Die Änderungen werden beim nächsten Aufruf des Programms aktiv.
Dieses Plugin bietet Ihnen die Möglichkeit ein Gästebuch in Ihre Webseite einzubauen. Über diese Software können Ihnen Ihre Besucher Nachrichten hinterlassen. Diese Nachrichten sind für alle Besucher sichtbar. Sie haben die Möglichkeit, sich bei neuen Einträgen per Mail informieren zu lassen. Außerdem sind die neuesten Nachrichten als RSS-Feed abrufbar.
Klicken Sie in Administrationsmenü auf "Gästebuch Setup". Im Abschnitt "E.-Mailbenachrichtigungen" können Sie festlegen, ob Sie bei neuen Einträgen automatisch per E.-Mail informiert werden wollen. Diese Option ist standardmäßig deaktiviert. Um diese zu aktivieren, klicken Sie auf den Schalter mit dem Text "aktivieren" und geben Ihre E.-Mailadresse in das Feld "Mail senden an" ein. (siehe Abbildung)
Um Ihre Änderungen zu speichern klicken Sie auf den Schalter "Änderungen speichern", oder klicken Sie auf "Abrechen", um zum Administrationsmenü zurückzukehren, ohne die Änderungen zu übernehmen.
Das Programm legt normalerweise neue Gästebücher bei Bedarf automatisch an. Dabei werden Basiseinstellungen verwendet, welche für alle Gästebücher gleichermaßen gelten (siehe oben). Falls Sie möchten, dass ein Gästebuch ein ganz spezielles Profil von Einstellungen verwendet, welche von den Basiseinstellungen aller anderen Gästebücher abweichen, gehen Sie wie folgt vor:
Ihr neues Gästebuch verlinken Sie so:
index.php?id=foo&action=guestbook_read
Wobei Sie statt "foo" den Namen Ihres Gästebuches einsetzen.
default
". (siehe
Abbildung)
Abbildung: Daten von anderem Profil verwenden
Genau so gehen Sie vor mit allen weiteren Layouts, die Sie erzeugen wollen.
Jedes neue Layout verlinken Sie genau so, wie ein echtes Gästebuch:
index.php?id=foo&action=guestbook_read
Wobei Sie statt "foo" den Namen des gewünschten Layouts einsetzen.
Um Ihr Gästebuch vor unerwünschter Werbung zu schützen stehen Ihnen verschiedene Sicherheitsoptionen zur Verfügung. Über das Menü "Gästebuch Setup" können Sie die maximale Anzahl der Einträge pro Person begrenzen.
Abbildung: Spamschutz
Zusätzliche Sicherheitseinstellungen bietet Ihnen die Verwendung des Plugins "Anti-Spam". Diese können Sie konfigurieren über das Menü "Anti-Spam Setup".
Um die volle Liste zu sehen oder neue Felder einzufügen bzw. alte Felder zu löschen, öffnen Sie die passende Strukturdatei "config/db/guestbook.db.xml".
Feldname | Typ | Pflichtfeld | Defaultwert | Beschreibung |
---|---|---|---|---|
GUESTBOOK_ID | integer | ja | <auto increment> | Primärschlüssel |
PROFILE_ID | string | nein | default | Schlüssel des passenden Profils. |
GUESTBOOK_IP | string | nein | <remote address> | IP des Autors eines Beitrages. |
GUESTBOOK_NAME | string | ja | - | Name des Autors |
GUESTBOOK_MESSAGE | string | ja | - | Text des Beitrages |
GUESTBOOK_MAIL | string | nein | null | Mailadresse des Autors eines Beitrages. |
GUESTBOOK_DATE | integer | ja | <current timestamp> | Erstellungsdatum eines Beitrages. |
GUESTBOOK_COMMENT | string | nein | null | Kommentar des Webmasters. |
Dieses Plugin bietet Schutz vor unerwünschter Werbung. Dieser
Schutz wirkt sich automatisch auf alle installierten Plugins aus. Die
Konfiguration erfolgt über ein zusätzliches "Setup"-Plugin. Dieses fügt
dem Administrationsmenü den Menüpunkt "Anti-Spam Setup" hinzu. Über
dieses Menü ist es möglich Einstellungen vorzunehmen.
Um Einstellungen vorzunehmen, gehen Sie wie folgt vor.
Abbildung: Anti-Spam Setup
Darstellung eines CAPTCHA im Programm. Hier: das
Gästebuch-Plugin
Dieses Plugin erlaubt es Ihnen, die Verbindungseinstellungen zu Ihrer Datenbank zu editieren. Weiterhin können Sie Tabellen installieren, erforderliche Daten übertragen und Backups erstellen.
Abbildung: Einstellungen der Verbindung zur Datenbank
Wählen Sie für die Option "Datenbank benutzen" den Wert "ja", um die eine Datenbankverbindung mit den angegebenen Verbindungsdaten zu verwenden. Die Installation der Datenbank läuft automatisch ab. Sie müssen somit nur im Fehlerfall von Hand eingreifen.
Sollte an einem dieser Punkte ein Fehler auftreten, so wird die Verbindung NICHT aktiviert und es wird eine Fehlermeldung angezeigt. Eine genaue Erläuterung des Fehlers finden Sie im Fehlerprotokoll. Beachten Sie bitte, dass dazu die Protokollierung aktiviert sein muss (siehe Kapitel "Logging und Fehlermeldungen").
Sie können im Fehlerfall die einzelnen Schritte, welche beim Aktivieren der Datenbankverbindung normalerweise automatisch durchgeführt werden, auch manuell durchführen. Gehen Sie dazu wie folgt vor.
Bitte beachten Sie auch die Kompatibilitätshinweise!
Hinweis: Dieser Schritt wird
normalerweise automatisch ausgeführt, wenn eine Datenbankverbindung aktiviert
wird. Das hier dargestellte Formular dient der manuellen Behandlung im
Fehlerfall.
Abbildung: Formular zum installieren der Tabellen
Es wird versucht, die zu den ausgewählten Datenbanken gehörenden Tabellen auf dem Datenbankserver zu erzeugen. Zu diesem Zweck werden gespeicherte SQL Dateien importiert, passend zum Typ der Datenbank. Voraussetzung ist, dass die Verbindung zur Datenbank vorher korrekt konfiguriert worden ist. Sie sollten die Datenbankverbindung jedoch nicht aktivieren bevor sie die erforderlichen Tabellen erzeugt haben.
In seltenen Fällen kann dieser Prozess fehlschlagen. Z.Bsp. wenn: keine Verbindung zum Datenbankserver möglich ist, für das gewählte DBMS kein SQL erzeugt werden kann, das erzeugte SQL fehlerhaft ist, eine andere Tabelle mit der gleichen Bezeichnung bereits existiert, oder der Nutzer nicht ausreichende Rechte zum Erzeugen der Tabellen besitzt. In diesen Fällen muss die Installation von Hand durchgeführt werden.
Die erforderlichen SQL-Dateien für das manuelle Erzeugen der Tabellen finden Sie im Kapitel "Anleitung für Fortgeschrittene" / "Konfiguration".
Hinweis: Dieser Schritt wird
normalerweise automatisch ausgeführt, wenn eine Datenbankverbindung aktiviert
wird. Das hier dargestellte Formular dient der manuellen Behandlung im
Fehlerfall.
Abbildung: Formular zum Kopieren der Inhalte der Tabellen zur Datenbank
Die Einträge in den Textdateien und der Datenbank werden miteinander abgeglichen. Bei diesem Vorgang werden KEINE Einträge gelöscht oder geändert, sondern lediglich neue hinzugefügt. Bei sehr großen Datenmengen kann es zu einem Timeout kommen. In diesem Fall wiederholen Sie die Prozedur mehrfach, bis alle Daten übertragen sind.
Hinweis: Diese Option funktioniert nur
wenn eine Datenbankverbindung aktiv ist.
Abbildung: Formular um ein Backup der Datenbank zu erstellen
Benutzen Sie diese Option um eine Sicherungskopie Ihrer Datenbank zu erstellen.
Mit diesem Skript können Sie Ihre Besucher den Inhalt Ihrer Homepage durchsuchen lassen. Um es verwenden zu können sind keine Programmierkenntnisse erforderlich.
Für die Installation dieses Pakets benötigen Sie die Java VM von Sun. Dabei handelt es sich um ein kostenloses Produkt, dass Sie unter http://java.sun.com herunterladen können.
Um eine bessere Geschwindigkeit der Suche zu gewährleisten, erstellt die Suchmaschine ein Verzeichnis der durchsuchbaren Dokumente. Dieses Verzeichnis nennt sich "Suchindex". Sie haben die Wahl, diesen entweder: 1) offline auf Ihrem eigenen Rechner, oder 2) online in Yana erstellen lassen wollen.
Sie müssen die Seiten Ihrer Homepage nicht von Hand eintragen. Dem Paket liegt ein kleines Java-Tool bei, dass Ihnen diese Arbeit abnehmen kann.
Um unter Windows herauszufinden, ob Java auf Ihrem System bereits installiert ist, genügt es meist nach der Datei "java.exe" zu suchen. Unter Windows, indem Sie im Startmenü auf "Suchen" > "Dateien und Ordner" gehen. Ist die Datei nicht vorhanden, müssen Sie Java noch installieren.
Diese Datei muss nach der Installation außerdem im Systempfad verknüpft sein. Dies können Sie prüfen, indem Sie in der Eingabeaufforderung "java" eingeben. Ihnen sollte nun eine Liste mit Optionen angezeigt werden. Falls nicht müssen Sie die Datei in den Systempfad eintragen.
Unter Windows-XP erledigen Sie dies in der Systemsteuerung unter "System" > "Erweitert" > "Umgebungsvariablen" > "Systemvariablen". Starten Sie den Rechner anschließend neu und versuchen Sie noch einmal "java" in der Eingabeaufforderung einzugeben. Sollte auch dies nicht von Erfolg gekrönt sein, bleibt Ihnen nichts anderes übrig, als Java neu zu installieren.
Bei älteren Versionen von Windows editieren Sie bitte die Datei
"autoexec.bat". Fügen Sie den folgenden Eintrag hinzu (vorher bitte Kopie anlegen):
SET PATH="JAVA-Verzeichnis\bin\java.exe;%PATH%"
Sie können erfahren welche Java-Version Sie installiert haben, indem Sie "java -version" in der Eingabeaufforderung eingeben.
Starten Sie die Datei start.bat mit Doppelklick. Das Programm hat eine grafische Oberfläche mit vielen bunten Icons und ist weitestgehend selbsterklärend. Es fragt die notwendigen Eingaben von Ihnen ab und erstellt anschließend per Klick einen Suchindex.
Tipp:
Sie müssen die Kommandozeile NICHT
benutzen. Es existiert eine grafische Nutzeroberfläche, welche Sie mit
der Datei "start.bat" ausführen können. Sollte diese jedoch nicht
funktionieren oder es Ihnen lieber ist, können Sie das Programm auch
von der Kommandozeile aus starten.
Sie können die Indexierung über die DOS-Eingabeaufforderung, oder wahlweise mit Hilfe der Datei "suchIndexErstellen.bat" ausführen.
Diese Datei ist anfangs so eingestellt, dass das aktuelle Verzeichnis inklusive seiner Unterverzeichnisse durchsucht wird. Möchten Sie das ändern, müssen Sie diese Datei editieren oder das Programm von Hand über die Eingabeaufforderung starten. Ansonsten genügt es die Datei einfach per Doppelklick auszuführen.
In der Eingabeaufforderung:
java -classpath index.jar suchindexErstellen VERZEICHNIS VERFOLGEN METATAGS
VERZEICHNIS: ist das Verzeichnis,
das durchsucht werden soll. Das aktuelle Verzeichnis ist zum Beispiel .\
das übergeordnete Verzeichnis ..\ heißt das
Verzeichnis Homepage, geben Sie homepage\ an usw.
Bitte verwenden Sie lediglich relative Pfadangaben (also nicht C:\\...)
sonst werden die Dateien mit Ihrer Festplatte verknüpft.
VERFOLGEN: gibt an, ob die in diesem Verzeichnis enthaltenen
Unterverzeichnisse ebenfalls durchsucht werden sollen oder nicht. Geben
Sie true an falls das geschehen soll oder false
falls nicht.
METATAGS: gibt an, ob die in den Meta-Tags enthaltenen Keywords
ebenfalls gespeichert werden sollen oder nicht. Geben Sie true
an, falls Sie dies möchten, oder false falls nicht.
Beispiele:
1) Wenn sich Ihre Homepage in "C:\Homepage" befindet und die Suchmaschine liegt in "C:\Homepage\suchmaschine" müssen die Java-Dateien in "C:\Homepage\suchmaschine" kopiert werden. Von hier muss auch der Aufruf erfolgen (auf der Kommandozeile):
java -classpath
index.jar suchindexErstellen ..\ true true
2) Angenommen Ihre Homepage befindet sich in "C:\Homepage", Ihre Suchmaschine befindet sich wieder im Verzeichnis "C:\Homepage\suchmaschine" und Sie möchten aber nur das Verzeichnis "C:\Homepage\test" ohne seine Unterverzeichnisse durchsuchen. Dann geben Sie folgendes ein:
java -classpath
index.jar suchindexErstellen ..\test\ false true
3) Ihre Homepage befindet sich (wieder) in "C:\Homepage", Ihre Suchmaschine befindet sich dieses Mal im gleichen Verzeichnis und Sie möchten nur das Verzeichnis "C:\Homepage\test" und seine Unterverzeichnisse - so lautet die Eingabe wie folgt:
java -classpath
index.jar suchindexErstellen .\test\ true true
Startdatei:
Öffnen Sie zunächst die Datei
suchIndexErstellen.bat
mit einem normalen Texteditor
(zum Beispiel Notepad). Hier finden Sie genau den gleichen Dateiaufruf
wie oben inklusive der Beschreibung. Ändern Sie die Einstellungen Ihren
Wünschen entsprechend, speichern und starten Sie die Datei.
Die Datenbank enthält alle in einem Dokument gefundenen
Begriffe, "Keywords" und den Titel der Seite.
Die Suche beschränkt sich auf HTML-Dokumente (*.htm, *.html, *.xml,
*.shtml). Gespeichert werden neben den gefundenen Suchbegriffen die URL
der Seite und die ersten 80 Zeichen als Beschreibung.
Nicht durchsucht werden außerdem alle Verzeichnisse, deren Name mit einem Unterstrich: "_" beginnt. Der Grund ist, dass einige Homepageprogramme (wie z.Bsp. Frontpage) diese Schreibweise nutzen um Systemverzeichnisse zu markieren, die natürlich nicht durchsucht werden sollen.
Mit der Datei " suchIndexErstellen.bat
" oder " start.bat
" einen neuen Suchindex
der Homepage erstellen und ins Netz laden. Dabei müssen die alten
Dateien " keywords.dat
" und "
documents.dat
" ersetzt werden. Falls vorhanden sollten
Sie den Cache der Suchmaschine leeren indem Sie im Verzeichnis "
cache/
" die Datei(en) " *.cache
" löschen.
Das kann passieren, wenn sich noch alte Daten im Cache der
Suchmaschine befinden. Löschen Sie dazu im Verzeichnis "
cache/
" alle Dateien mit der Endung "
*.cache
" und versuchen Sie es erneut.
Das Anzeigen der Trefferliste erledigt ein JavaScript. Das macht die Suchmaschine extrem schnell und entlastet den Server, weil beim Blättern durch die Suchergebnisse keine Daten vom Server nachgeladen werden müssen. Allerdings: muss dazu JavaScript in ihrem Browser aktiviert sein. Wenn die Seite leer bleibt prüfen Sie bitte ob JavaScript deaktiviert ist oder durch eine Firewall blockiert wird.
Im Verzeichnis "tools" liegen 3 Dateien "start.bat", "suchIndexErstellen.bat" und "searchIndex.bat". Alle tun exakt das gleiche. Nur, dass die Datei "start.bat" eine grafische Oberfläche aufruft, die alle Daten über ein Menü abfragt. Die anderen beiden starten das Programm direkt von der Kommandozeile aus. Dort müssen Sie die Parameter von Hand direkt in der Datei ändern. Dabei zeigt "searchIndex.bat" die Beschreibung der Parameter in Englisch und "suchIndexErstellen.bat" die gleiche Beschreibung in deutscher Sprache an. Wählen Sie die Lösung, die Ihnen am besten gefällt.
Vermutlich haben Sie den Suchindex noch nicht erstellt oder die Dateien im falschen Verzeichnis abgelegt. Wie Sie einen Suchindex erstellen können Sie im Abschnitt "Suchindex erstellen" lesen.
Vermutlich haben Sie vergessen einige wichtige Dateien, ins Internet zu übertragen. Bitte prüfen Sie ob diese Dateien vorhanden sind.
Das kann passieren wenn nicht ausreichende Zugriffsrechte
gesetzt sind. Prüfen Sie bitte mit ihrem FTP-Programm ob für die Ordner
" cache/
" und " config/
", sowie alle Unterverzeichnisse und Dateien ausreichende
Zugriffsrechte (lesen UND schreiben) gesetzt sind. Sie erreichen dies
unter UNIX zum Beispiel mit dem Befehl CHMOD 777. Eine detaillierte
Erläuterung der Zugriffsrechte finden Sie in der Installationsanleitung
im Abschnitt für Anfänger.
Bitte prüfen Sie, ob Sie mindestens Version 1.4.2 der Java Virtual Machine installiert haben. Geben Sie dazu in der Eingabeaufforderung ein "java -version". Sollte Sie eine ältere Version haben, laden Sie sich aus dem Netz unter java.sun.com kostenlos eine aktuellere Version der Java Virtual Machine herunter. Oder versuchen Sie die Datei "suchIndexErstellen.bat" um das Programm von der Kommandozeile aus zu steuern. Das ist zwar nicht so bequem, dafür reicht dann allerdings schon Version 1.3 der Java Virtual Machine aus.
Dieses Plugin lädt eine RSS Datei Ihrer Wahl und erzeugt eine HTML-Seite, die Sie nach Ihren Wünschen anpassen können. Dazu können Sie das Template im Verzeichnis "skins/default/rss/template.html" editieren.
Das Plugin ist ideal geeignet für Leute, die bereits einen RSS-Feed für ihre Homepage haben oder erstellen möchten und gleichzeitig (für Leute ohne RSS- Reader) eine Newsseite anbieten wollen. Mit diesem Plugin spart man sich die doppelte Führung von Newsseite und RSS-Feed. Anstatt neue Meldungen in HTML und XML separat zu schreiben, braucht man nur noch den Feed zu aktualisieren. Die HTML-Seite wird automatisch erzeugt.
Sie können sich nun eine Testseite ansehen, indem sie index.php?action=get_news aufrufen
Wenn Sie einen eigenen RSS-Feed einbinden möchten, dann wählen Sie im Administrationsmenü aus der Spalte "Optionen" den Eintrag "RSS-to-HTML Setup".
Das SDK unterstützt den Entwickler durch eine grafische Oberfläche. Die grafische Oberfläche führt dabei durch vier Schritte, in denen Aussehen, Verhalten und allgemeine Informationen zur Anwendung und zum Urheber bereitgestellt werden können.
Es wird dringend empfohlen, das SDK nur auf Webservern zu installieren, welche für den öffentlichen Zugriff gesperrt sind. Beispielsweise auf einer lokalen Arbeitsstation, welche nicht über Netzwerk erreichbar ist.
Stellen Sie sicher, dass das Programm Schreibrechte für die Verzeichnisse "plugins" und "config" besitzt.
Falls Sie eine Einführung in die Benutzung des SDK wünschen, finden Sie diese im Kapitel "Plugins und Anwendungen erstellen". Ein praktisches Anwendungsbeispiel finden Sie im Einführungstutorial, in Kapitel 3 "Erstellen eines neuen Plugins".
error_reporting(0);in folgenden Text:
error_reporting(E_ALL);
ErrorUtility::setErrorReporting(YANA_ERROR_ON);
Viele Editoren können die Arbeit mit dem Yana Framework erleichtern. Um Sie beim Übersetzen, Entwickeln neuer Plugins, oder Schreiben von Skins zu unterstützen, stehen Syntax-Highlighter und Code-Templates für verschiedene Editoren zur Verfügung.
Der folgende Abschnitt soll Ihnen Beispiele zeigen und demonstrieren, wie diese Werkzeuge Ihre Arbeit erleichtern können.
Für das Editieren der Konfigurationsdateien, Templates und Plugins des Yana Framework stehen Syntax-Highlighter und Code-Templates für "ConTEXT" zur Verfügung. ConTEXT ist ein Editor für Programmierer. Sie finden ihn im Internet unter der Adresse http://context.cx. Das Programm ist kostenlos und bietet Unterstützung für weit mehr als 50 Programmiersprachen und Dateiformate. Darunter das komplette Yana Framework.
Zur Installation der Highlighter und Templates für das Yana Framework installieren Sie zuerst ConTEXT. Öffnen Sie anschließend das Installationsverzeichnis des Editors und kopieren Sie die "ConTEXT Highlighter Files" (*.chl) in das Verzeichnis "Highlighters" und die "ConTEXT Template Files" (*.ctpl) in das Verzeichnis "Template" (siehe Abbildung). Falls Sie ConTEXT noch geöffnet haben, starten Sie den Editor bitte neu.
Abbildung: ConTEXT Installationsverzeichnis
ConTEXT bietet die Möglichkeit, die Hilfe des Yana Framework aus dem Editor heraus zu nutzen. Um diese Einzubinden gehen Sie wie folgt vor:
1. Öffnen Sie das Menü "Einstellungen" > "Umgebungseinstellungen"
Abbildung: Umgebungseinstellungen öffnen
2. Wechseln Sie in das Menü "Verschiedenes" und wählen Sie aus der Liste den Eintrag "Yana Framework" beziehungsweise "Yana Framework Templates" aus.
3. Klicken Sie auf die Schaltfläche "bearbeiten".
Abbildung: Hilfedateien zuordnen
4. Wählen Sie den Dateityp "all files (*.*)" aus, durchsuchen Sie Ihre Festplatte nach der Datei "index.html" dieses Handbuchs und wählen Sie mit der Maus diese Datei aus.
5. Klicken Sie auf die Schaltfläche "Öffnen"
Abbildung: Datei "index.html" als Startseite auswählen
5. Speichern Sie die Änderung durch Klick auf "OK".
Die erforderlichen Dateien finden Sie auf den folgenden Webseiten:
Öffnen Sie eine Konfigurationsdatei (zum Beispiel ein Datenbankschema aus dem Verzeichnis yana/config/db/) mit ConTEXT und wählen Sie aus der Liste der Highlighter den Eintrag "Yana Framework".
Abbildung: Bearbeiten eines Datenbankschemas mit ConTEXT
Öffnen Sie ein Template mit ConTEXT und wählen Sie aus der Liste der Highlighter den Eintrag "Yana Framework Templates".
Abbildung: Bearbeiten einer Templatedatei mit ConTEXT
Zum Einfügen von Code-Templates verwenden Sie die Tastenkombination <CTRL> + <j>, oder wählen Sie aus dem Menü "Format" den Eintrag "Textbaustein einfügen". Ein Auswahlmenü wird angezeigt. Dieses besteht aus zwei Teilen: Links sehen Sie ein Tastenkürzel und rechts eine Beschreibung. Wählen Sie mit der Maus oder den Pfeiltasten einen Baustein aus und drücken Sie <ENTER> zum Einfügen.
Sie können die Auswahl einzuschränken, indem Sie die Anfangsbuchstaben eines Bausteins eingeben. Wenn nur 1 passender Baustein zur Verfügung steht, wird dieser automatisch eingefügt und das Auswahlmenü wird nicht angezeigt.
Zum Beispiel: schnelles Erstellen eines Datenbankschemas.
Das Ergebnis demonstriert die folgende Abbildung.
Abbildung: Erstellen einer neuen Tabelle mit wenigen Handgriffen
Weitere Abkürzungen können Sie der Auswahlliste entnehmen.
Für das Editieren der Konfigurationsdateien, Templates und Plugins des Yana Framework stehen Syntax-Highlighter und Code-Templates für "PSPad" zur Verfügung. PSPad ist ein Texteditor für Webentwickler. Sie finden ihn im Internet unter der Adresse http://www.pspad.com. Das Programm ist als Freeware kostenlos erhältlich.
PSPad kann auch ohne Installation von einem USB-Stick gestartet werden.
Zur Installation der Highlighter und Templates für das Yana Framework installieren Sie zuerst PSPad. Öffnen Sie anschließend das Installationsverzeichnis des Editors und kopieren Sie die "Highlighter Files" (*.ini) in das Verzeichnis "Syntax" und die "Template Files" (*.def) in das Verzeichnis "Context" (siehe Abbildung). Falls Sie PSPad noch geöffnet haben, starten Sie den Editor bitte neu.
Abbildung: PSPad Installationsverzeichnis
Um die Installation abzuschließen, müssen Sie die neuen Dateien in PSPad noch aktivieren.
Abbildung: Aktivieren der Highlighter
Die erforderlichen Dateien finden Sie auf den folgenden Webseiten:
Öffnen Sie eine Plugin-Definitionsdatei (plugins/*.config) mit PSPad.
Um den Highlighter auszuwählen, klicken Sie auf die Schaltfläche "Change document syntax highlight" (siehe Abbildung).
Abbildung: eine Konfigurationsdatei des Yana Frameworks in PSPad,
rechts mit aktivem Code-Browser
Wählen Sie den Eintrag "Yana Framework" beziehungsweise "Yana Framework Templates" und klicken Sie auf "OK".
Abbildung: Syntax Highlighter auswählen
Ebenso wie ConTEXT kennt PSPad Textbausteine. Diese werden in PSPad "Clips" genannt und sind über das Tastenkürzel <CTRL> + <SPACE> erreichbar.
Die Handhabung ist identisch zu ConTEXT. Ein Auswahlmenü wird angezeigt. Dieses besteht aus zwei Teilen: Links sehen Sie ein Tastenkürzel und rechts eine Beschreibung. Wählen Sie mit der Maus oder den Pfeiltasten einen Baustein aus und drücken Sie <ENTER> zum Einfügen.
Sie können die Auswahl einzuschränken, indem Sie die Anfangsbuchstaben eines Bausteins eingeben.
Abbildung: Verwendung von "Clips" in PSPad
Dieses Programm verwendet Musterseiten, sogenannte "Templates". Was auch immer Sie auf diesen Seiten ändern, ändert auch das Aussehen und Verhalten der Anwendung. Diese Dateien befinden sich im Skinverzeichnis. Sie können diese Dateien so wie normale HTML-Seiten in Ihrem Webeditor laden und ändern. Zum Ändern der Dateien sind keine HTML-Kenntnisse notwendig, bei größeren Änderungen sind diese allerdings vorteilhaft.
In jedem Fall sollten Sie sich Kopien der Originaldateien anlegen, bevor Sie Änderungen vornehmen.
Tutorials zum Erstellen eigener Templates finden Sie auf der Smarty-Homepage unter: http://smarty.net
Wenn Sie nicht nur ein bereits existierendes Template editieren, sondern ein neues - oder vielleicht sogar einen neuen Skin - erstellen wollen, dann genügt es nicht, die Template-Dateien zu editieren. Sondern Sie müssen auch die Konfiguration der Templates und Skins verstehen und anwenden.
Dies ist jedoch sehr einfach und erschöpft sich in zwei Konfigurationsdateien. Eine davon für Ihre neuen Templates und die andere für Ihren neuen Skin.
Im Folgenden ein einfaches Beispiel.
<SKIN_INFO> <NAME>mein Skin</NAME> <DESCRIPTION>das ist eine Beschreibung meines Skins</DESCRIPTION> <AUTHOR>mein Name</AUTHOR> <CONTACT>meine Webseite</CONTACT> <LOGO>%SKINDIR%mein_skin/data/preview.gif</LOGO> <DIRECTORY>mein_skin/</DIRECTORY> </SKIN_INFO>
Die Syntax ist weitgehend selbsterklärend. Die Felder "Name", "Description" (Beschreibung), "Author" (Autor) und "Contact" (Kontakt) sind Freitext. Für das Feld "Name" können Sie sich einen beliebigen Namen ausdenken, der Ihren Skin beschreibt. Ebenso beliebig ist das Feld "Description" (Beschreibung). Achten Sie darauf, dass als Whitespace nur Leerzeichen erlaubt sind. Sie können einen Zeilenumbruch bei Bedarf einfügen, indem Sie den Text "[br]" verwenden. Das Feld "Author" (Autor) sollte Ihren Namen enthalten und das Feld "Contact" (Kontakt) sinnvollerweise eine Mail- oder Internetadresse, über welche man Sie erreichen und/oder Updates downloaden kann.
Das Feld "Logo" gibt eine Vorschaugrafik an. Der Platzhalter %SKINDIR% bezieht sich auf das Verzeichnis, in welchem die Skins gespeichert sind und sollte stets angegeben werden. Die Grafik sollte vorzugsweise im GIF-, PNG- oder JPEG-Format gespeichert sein und etwa 300x300 Pixel groß sein.
Das Feld "Directory" muss stets angegeben werden. Es gibt an in welchem Verzeichnis der Skin gespeichert ist.
Im Folgenden ein einfaches Beispiel.
<MY_TEMPLATE> <FILE>template.html</FILE> <STYLE> <0>style/default.css</0> <1>foo1/foo2.css</1> <MEIN_CSS>foo3/foo4.css</MEIN_CSS> </STYLE> <SCRIPT> <0>foo5/foo6.js</0> <MEIN_SCRIPT>foo7/foo8.js</MEIN_SCRIPT> </SCRIPT> <LANGUAGE> <0>guestbook</0> <1>admin</1> </LANGUAGE> </MY_TEMPLATE>
Beachten Sie, dass "MY_TEMPLATE" als Identifier fungiert, welcher das Template identifiziert. Sie können diese Id in den Konfigurationsdateien Ihrer Plugins verwenden, um auf das Template zu verweisen. Der Text kann beliebig gewählt werden. Achten Sie jedoch darauf, dass die Id keine Sonderzeichen oder Leerzeichen enthält, mit einem Buchstaben beginnt und über die gesamte Anwendung hinweg eindeutig ist. Groß- und Kleinschreibung spielt keine Rolle.
Es gibt 4 Felder: "File", "Style", "Script" und "Language". Das Feld "File" gibt den Dateinamen an. Die restlichen Felder sind optional und dienen der Automatisierung.
Das Feld "Language" enthält Verweise auf eine oder mehrere Dateien, welche die Sprachinformationen für dieses Template enthalten. Beispielsweise bezieht sich der Wert "guestbook" auf die Datei "languages/XX/guestbook.config", wobei der Text "XX" automatisch vom System durch die vom Nutzer gewählte Sprache ersetzt wird. Zum Beispiel "de" für Deutsch beziehungsweise "en" für Englisch.
Das Feld "Style" kann mehrere Verweise auf Stylesheets enthalten. Ebenso enthält das Feld "Script" einen oder mehrere Verweise auf JavaScript-Dateien. Die angegebenen Dateien werden jeweils automatisch eingebunden, wenn das Template aufgerufen wird.
Hinweis: Ist in einem Skin ein erforderliches Template nicht definiert oder sind Eigenschaften dieses Templates ("Styles", "Script", "Languages") nicht erneut erklärt, so fällt das Programm automatisch auf den "Default"-Skin zurück.
Dies geschieht wie folgt.
Dieses Verhalten mag zunächst unlogisch erscheinen, hat jedoch einen durchaus einen tieferen Sinn. Es erlaubt einzelne Stylesheets oder Scripts in einem neu erstellten Skin ganz gezielt auszutauschen. Gleichzeitig gestattet es aber auch einzelne Stylesheets oder Scripts von diesem Mechanismus auszuschließen. Beide Variante kommen vor und haben ihre Einsatzgebiete.
Ein weiteres Beispiel zur Illustration dieses Verhaltens. Die folgende Definition tauscht für das Template "MY_TEMPLATE" nur die CSS-Datei "MEIN_CSS" aus dem Default-Skin durch eine andere aus. Alle anderen Einstellungen bleiben unverändert.
<MY_TEMPLATE> <STYLE> <MEIN_CSS>foo/bar.css</MEIN_CSS> </STYLE> </MY_TEMPLATE>
Wie Sie in diesem Beispiel sehen, wird keine neue HTML-Vorlage festgelegt, sondern es wird wieder die Vorlage des Default-Skin verwendet. Das heißt: es ist nicht erforderlich die HTML-Vorlage aus dem Default-Skin in den neuen Skin zu kopieren, oder zu editieren um ein neues Layout zu erzeugen. Dies vermeidet unnötige Redundanz und erleichtert Ihnen die Pflege Ihres HTML-Codes.
* "erforderlich" meint in diesem Fall "ungleich NULL"
Platzhalter | Typ | erforderlich * | Defaultwert | Herkunft | Beschreibung |
---|---|---|---|---|---|
PHP_SELF | String | ja | - | PHP | Name der ausgeführten Skriptdatei. |
REMOTE_ADDR | String | ja | - | PHP | Die IP-Adresse des Clients. |
SETTINGS.WEBSITE_URL | String | nein | - | aufrufende URL | komplette URL des Skriptes (inkl. http://...) |
REQUEST_URI | String | nein | - | aufrufende URL | aufgerufener Pfad des Skriptes, inklusive Parameter (/yana/index.php?...) |
QUERY_STRING | String | nein | - | aufrufende URL | an das Skripte übergebene Parameterliste |
ID | String | ja | default | GET/POST | ID-Code des gerade aktiven Profils. |
ACTION | String | nein | <empty> | GET/POST | Name der Aktion welche gerade ausgeführt wird bzw. welche ausgeführt werden soll. |
TARGET | String | nein | <empty> | GET/POST | Ziel der Aktion welche gerade ausgeführt wird bzw. welche ausgeführt werden soll. (bspw. die ID eines Datensatzes) |
SESSION_NAME, SESSION_ID | String | nein | <empty> | GET/POST | Name und ID-Code der gerade laufenden Session (sollten bei allen internen Links angegeben werden) |
PAGE | integer | nein | 0 | GET/POST | Die Nummer des Datensatzes, ab welchem mit der Anzeige begonnen werden soll. (falls erforderlich) |
ATIME | string | ja | - | Dateiattribut | Fügt Datum und Zeit des letzten Zugriffs auf das
HTML-Template an dieser Stelle ein: [%$ATIME|date%] |
MTIME | string | ja | - | Dateiattribut | Fügt an dieser Stelle das Datum ein, an welchem das
HTML-Template zuletzt geändert worden ist: [%$MTIME|date%] |
CTIME | string | ja | - | Dateiattribut | Fügt an dieser Stelle das Datum ein, an welchem das
HTML-Template erstellt worden ist: [%$CTIME|date%] |
LANGUAGE | Array | ja | - | Sprachdatei(en) | Array, welches alle Textstrings der gerade ausgewählten Übersetzung enthält. |
PROFILE | Array | ja | - | Profildatei | Array, welches alle Einstellungen des gerade aktiven
Profils enthält. Im Folgenden einige Beispiele. Beachten Sie, dass alle hier genannten Felder auch einen NULL-Wert enthalten dürfen. |
PROFILE.BGCOLOR, PROFILE.BGIMAGE |
String | nein | - | Profildatei | Hintergrundfarbe und Hintergrundbild der Webseite |
PROFILE.PFONT, PROFILE.PSIZE, PROFILE.PCOLOR |
String | nein | - | Profildatei | Schriftart, Schriftgröße, Schriftfarbe für Standardabsätze (P-Tags) |
PROFILE.HFONT, PROFILE.HSIZE, PROFILE.HCOLOR |
String | nein | - | Profildatei | Schriftart, Schriftgröße, Schriftfarbe für Überschriften (H1-,H2-,H3-Tags) |
SKIN_INFO | Array | nein | - | Skindatei | Informationen zum gewählten Skin |
LANGUAGE_INFO | Array | nein | - | Sprachdatei | Informationen zur gewählten Sprache |
LANGUAGE | Array | nein | - | Sprachdatei(en) | Übersetzungen (Texte) |
SETTINGS.WEBSITE_URL | String | nein | - | Sprachdatei(en) | komplette URL des Skriptes (inkl. http://...) |
Dieses Framework verwendet die "Smarty Template-Engine". Diese Engine besitzt Ihre eigene Dokumentation, welche kostenlos unter der Adresse http://smarty.net/docs.php zum Download bereit steht.
Es ist Ihnen gestattet, die Engine durch selbst geschriebene Funktionen zu erweitern. Auf diese Weise können Sie die Syntax der verwendeten Templates quasi beliebig erweitern. Sie finden die Engine im Verzeichnis "engine/". Eine Anleitung dazu finden Sie im Referenzhandbuch der Engine. Änderungen an der Engine sind jedoch nur Experten zu empfehlen.
Hinweis zu Lizenzen: Bevor Sie Änderungen vornehmen, beachten Sie bitte die Lizenzhinweise.
Die Syntax der verwendeten Version der "Smarty Template-Engine" weicht in einigen Punkten vom Referenzhandbuch ab. Der folgende Abschnitt beschreibt diese geänderte Syntax.
Anders als in der Originalversion von Smarty verwendet diese Version nicht die Zeichen '{' und '}' als öffnende und schließende Tags für die Auszeichnung von Smarty-Codes, sondern die unverfänglicheren Strings: '[%' und '%]'. Also beispielsweise NICHT "{$variable}", sondern "[%$variable%]". Der Grund ist, dass die ursprünglichen Zeichen in den meisten HTML-Dokumenten zu häufig im Fließtext bzw. in Skripten oder Stylesheets auftauchen, was zu Problemen bei der Abarbeitung der Templates führen kann. Daher wurden die Tags vorsorglich auf diese unverfänglichere Variante geändert. (Dieses Vorgehen wird zudem auch im Handbuch der Engine für solche Fälle empfohlen.)
Anders als in der Originalversion erlaubt diese Version auch den Einsatz einer verkürzten Syntax für das Einsetzen einfacher Variablen. Statt der etwas umständlicheren Schreibweise "[%$VARIABLE%]" ist in dieser Version auch folgende Schreibweise gestattet: "%VARIABLE%". Dies betrifft allerdings ausschließlich Variablen. Auf alle anderen Smarty-Codes ist dies NICHT anwendbar.
Weil Smarty zwischen Groß- und Kleinschreibung unterscheidet wurde zur Vereinfachung festgelegt, dass Variablennamen prinzipiell in Großbuchstaben benannt sein sollten. Während die Namen von Funktionen und anderen Codes ausschließlich Kleinbuchstaben enthalten sollten. Aus Gründen der Übersichtlichkeit ist dringend zu empfehlen, sich an diese Konvention zu halten.
In dieser Version können Verweise auf Dateien (Links, Grafiken, CSS, Skripte, etc.) als relative Pfadangaben gespeichert werden. Dateipfade werden beim Laden der Seite automatisch korrigiert. Es ist also nicht mehr erforderlich, ausschließlich absolute Dateipfade zu verwenden.
Smarty läuft in dieser Version im sicheren Modus (security=true). Das Einbetten von PHP-Codes in Templates ist nicht gestattet. Außerdem sind folgende Funktionen deaktiviert: include, include_php, php.
[%captcha [ id="<string>" ] %]
Attribut | Typ | erforderlich | Defaultwert | Beschreibung |
---|---|---|---|---|
id | string | nein | - | Wert für das Attribut "id" des Tags "input" |
Die Funktion "captcha" wird verwendet, um eine Grafik anzuzeigen, welches Text enthält, den der Besucher lesen und in das daneben eingeblendete Eingabefeld eingeben muss. Dies ist eine allgemein gebräuchliche Variante zum Schutz vor Spam.
Der Parameter "id" ist optional. Er kann beispielsweise verwendet werden, wenn eine Beschreibung in einem "label" angezeigt werden soll.
[%captcha%]
Abbildung: Darstellung im Browser
<label for="myCaptcha">Bitte geben Sie den Text
auf dem Bild ein</label>
[%captcha id="myCaptcha"%]
Weitere Hinweise finden Sie auch im Kochbuch für Entwickler, Kapitel "Verwenden eines CAPTCHA".
[%create template="<string>" file="<string>" table="<string>" [ where="<string>" ] [ desc="<boolean>" ] [ sort="<string>" ] [ page="<integer>" ] [ entries="<integer>" ] [ titles="<boolean>" ] [ on_new="<string>" ] [ on_edit="<string>" ] [ on_delete="<string>" ] [ on_search="<string>" ] %]
Attribut | Typ | erforderlich | Defaultwert | Beschreibung |
---|---|---|---|---|
template | string | ja | - | Name des Templates, welches zum Generieren der GUI
verwendet werden soll. Erlaubte Werte sind: view_seperated, view_details, view, new, edit, search |
file | string | ja | - | Pfad der Strukturdatei welche verwendet werden soll. |
table | string | ja | - | Name der Tabelle, welche verwendet werden soll |
show | string | nein | - | durch Kommata getrennte Liste von Spalten der Tabelle, welche in der Ausgabe angezeigt werden sollen (Kleinschreibung verwenden) |
hide | string | nein | - | durch Kommata getrennte Liste von Spalten der Tabelle, welche in der Ausgabe NICHT angezeigt werden sollen (Kleinschreibung verwenden) |
where | string | nein | <empty> | wird verwendet um die WHERE-Klausel für die
SQL-Anfrage zu generieren. Syntax: <FELDNAME1>=<WERT1>[,<FELDNAME2>=<WERT2>[,...]] |
desc | boolean | nein | false | Gibt an, ob die Einträge aufsteigend (false) oder absteigend (true) sortiert werden sollen. |
sort | string | nein | <primary key> | Name der Spalte, nach welcher die Einträge sortiert werden sollen |
page | integer | nein | 0 | Nummer des ersten Eintrags der angezeigt werden soll |
entries | integer | nein | 5 | Anzahl der insgesamt anzuzeigenden Einträge |
titles | boolean | nein | true | Legt fest, ob Attributnamen angezeigt werden sollen oder nicht. |
on_new | string | nein | - | Name der Aktion welche ausgelöst werden soll wenn ein neuer Eintrag gespeichert werden soll |
on_edit | string | nein | - | Name der Aktion welche ausgelöst werden soll wenn geänderte Einträge gespeichert werden sollen |
on_delete | string | nein | - | Name der Aktion welche ausgelöst werden soll wenn ausgewählte Einträge gelöscht werden sollen |
on_search | string | nein | - | Name der Aktion welche ausgelöst werden soll um eine Suchanfrage zu bearbeiten und die Trefferliste zu erzeugen |
on_download | string | nein | download_file | Name der Aktion welche ausgelöst werden soll wenn der Nutzer eine Datei oder ein Bild herunterladen möchte |
layout | int | nein | 0 | Sollte ein Formular mehrere Darstellungsmöglichkeiten bieten, so können Sie mit diesem Parameter zwischen diesen wechseln. |
Die Funktion "create" generiert automatisch eine GUI für eine gewählte Datenbank. Voraussetzung ist das Vorhandensein einer gültigen Strukturdatei, welche die Datenbank beschreibt.
[%create template="edit" file="database.config" table="bookstore"%]
Ein Beispiel für eine Funktion, zum Download einer Datei (Argument "on_download"):
<?php function myDownload($ARGS) { if ($source = DbBlob::getFileId() === false) { return false; } // Download einer Datei: if (preg_match('/\.gz$/', $source)) { $dbBlob = new DbBlob($source); $dbBlob->read(); header('Content-Disposition: attachment; filename=' . $dbBlob->getPath()); header('Content-Length: ' . $dbBlob->getFilesize()); header('Content-type: ' . $dbBlob->getMimeType()); print $dbBlob->get(); // Download einer Grafik: } else { $image = new Image($source); $image->outputToScreen(); } exit; } ?>
Achtung!
Diese Funktion prüft nicht automatisch, ob der Nutzer die ausgewählte
Datei im Sinne der Semantik Ihres Programms herunterladen "darf". Dies
ist leider auch gar nicht möglich, ohne die Kriterien zu kennen, welche
Sie innerhalb Ihres Programms dafür anwenden. Daher bleibt es an dieser
Stelle Ihnen überlassen zu verifizieren, dass der Benutzer die
notwendige Berechtigung besitzt, um die gewünschte Datei einzusehen.
[%embeddedTags [ show="<string>" ] [ hide="<string>" ] %]
Attribut | Typ | erforderlich | Defaultwert | Beschreibung |
---|---|---|---|---|
show | string | nein | * | eine durch Kommata getrennte Liste der Tags, die angezeigt werden sollen |
hide | string | nein | - | eine durch Kommata getrennte Liste der Tags, die ausgeblendet werden sollen |
Die Funktion "embeddedTags" generiert automatisch eine Schaltflächen, mit denen der Gast Ihrer Webseite beim Schreiben eines neuen Eintrags Text formatieren kann (fett, kursiv, etc.).
Die Liste "show" kann verwendet werden, um Tags festzulegen, welche angezeigt werden sollen und die Liste "hide" kann man benutzen, wenn Sie möchten, dass ganz bestimmte Tags nicht dargestellt werden.
Sie können in der Liste "show" mit dem Zeichen "-" Zeilenumbrüche und mit dem Zeichen "|" Trennstriche in die Ausgabe einfügen.
<textarea id="text"></textarea>
Abbildung: Darstellung der Tag-Leiste (mit allen Tags)
<!-- Alle Tags einblenden -->
[%embeddedTags%]
<!-- Die Tags "u", "i" und "b" einblenden -->
[%embeddedTags show="b,u,i"%]
<!-- Alle Tags außer "url" und "mail" einblenden -->
[%embeddedTags hide="url,mail"%]
<!-- Die Tags "u","i","b", einen Trennstrich und dann den Tag "url" anzeigen -->
[%embeddedTags show="u,i,b,|,url"%]
[%import [preparser="true"] file="<string>"%]
[%import [preparser="true"] id="<string>"%]
Attribut | Typ | erforderlich | Defaultwert | Beschreibung |
---|---|---|---|---|
file | string | ja | - | Pfad der einzufügenden Datei |
preparser | boolean | nein | false | bestimmt ob die Datei vor (true) oder während (false) des Parsens des Templates importiert werden soll |
Oder alternativ mit folgenden Parametern:
Attribut | Typ | erforderlich | Defaultwert | Beschreibung |
---|---|---|---|---|
id | string | ja | - | Id des einzufügenden Templates |
preparser | boolean | nein | false | bestimmt ob die Datei vor (true) oder während (false) des Parsens des Templates importiert werden soll |
Die Funktion "import" ersetzt die verschiedenen ursprünglichen Funktionen zum Einfügen von Dateien durch eine einheitliche Funktion. Sie unterscheidet sich außerdem in der Art, wie die Dateien behandelt werden. Die Funktion "import" behandelt die zu importierende Datei wie ein eigenständiges Template. Dieses hat mehrere Vorteile: das eingefügte Template unterliegt bspw. den selben Sicherheitseinschränkungen wie das Basistemplate. Außerdem (und noch viel wichtiger:) sorgt dieses Vorgehen dafür, dass die Korrektur enthaltener Pfadangaben korrekt arbeiten kann.
Der Parameter "file" gibt den Namen der Datei an, welche importiert werden soll.
Alternativ kann der Parameter "id" verwendet werden, um statt den Pfad und Dateinamen fest im Template vorzugeben, die Id des Templates anzugeben. Das Framework bestimmt den zu der Id passenden Dateinamen zur Laufzeit automatisch. Dies hat den Vorteil, dass die Datei umbenannt oder in einen anderen Pfad verschoben werden kann, ohne dass die Verweise auf diese Datei in allen anderen Templates korrigiert werden müssen.
Das Flag "preparser" bestimmt, wann eine Datei importiert werden soll: BEVOR oder WÄHREND der Parser das Template abarbeitet. Wird es gesetzt, wird die Datei VOR dem eigentlichen Parsen eingefügt. Das Flag "preparser" sollte beispielsweise immer dann verwendet werden, wenn das importierte Template auf Variablen zugreifen muss, welche durch das Basistemplate gesetzt werden. Klassisches Beispiel sind Templates, welche innerhalb des Körpers von Schleifen importiert werden. ("foreach", "section") Diese benötigen das Flag "preparser", falls sie auf die Schleifenvariablen zugreifen können müssen. Alternativ können Sie der Anweisung "Import" eine Liste aller Variablen übergeben, auf welche Sie innerhalb des Templates zugreifen müssen.
Achtung! Wird der Parameter "preparser" verwendet,
so wird das importierte Template nicht einzeln geparst, übersetzt und
im Cache gespeichert, sondern in den Quellcode des Templates kopiert,
welches die Import-Anweisung enthält. Es wird zur Laufzeit nicht geprüft,
ob sich der Inhalt des importierten Templates seit dem letzten Aufruf geändert
hat. Wenn Sie das importierte Template ändern, müssen Sie daher den
Template-Cache explizit leeren, damit die Änderungen wirksam werden.
Datei "hello_world.html"
Hello World!
Datei "template.html"
<p>[%import file="hello_world.html"%]</p>
Datei "default.config"
<hello>
<file>hello_world.html</file>
</hello>
Datei "template.html"
<p>[%import id="hello"%]</p>
Datei "hello_world.html"
[%if $foo%]
[%$bar%]
[%/if%]
Datei "template.html"
<p>[%import file="hello_world.html" foo=true bar="Hello
World!"%]</p>
<p>Hello World!</p>
[%preview [ width="<integer>" ] [ height="<integer>" ] %]
Attribut | Typ | erforderlich | Defaultwert | Beschreibung |
---|---|---|---|---|
width | integer | nein | 380px | Breite in Pixel |
height | integer | nein | 50px | Höhe in Pixel |
Die Funktion "preview" erzeugt ein Vorschaufenster auf einen Eintrag, welchen der Besucher geschrieben hat.
Im Text enthaltene Smilies und Tags werden dabei grafisch dargestellt. Dadurch hat der Besucher die Möglichkeit vor dem Abschicken des Formulars zu prüfen, wie sein Beitrag aussehen wird.
Beim Aufruf der Funktion werden automatisch die erforderlichen JavaScript-Dateien eingebunden. Außerdem wird eine Schaltfläche mit der Aufschrift "Vorschau" erstellt. (In der englischen Version lautet die Beschriftung "Preview".) Beim Anklicken wird oberhalb dieser Schaltfläche ein Fenster eingeblendet, welches die Vorschau zeigt.
<textarea id="text"></textarea>
[%preview%]
Abbildung: Die Vorschau wird durch Anklicken der Schaltfläche
"Vorschau" über einen "AJAX HTTP-Request" vom Server geladen
Abbildung: Darstellung der Vorschau im Browser
Die Attribute "width" und "height" geben Breite und Höhe des Vorschaufensters an. Diese Werte werden als CSS-Anweisungen umgesetzt. Wenn Sie diese verwenden möchten, achten Sie daher bitte darauf, dass Sie eine Maßeinheit (zum Beispiel "px" für Pixel) angeben müssen. Prozentuale Angaben, wie "70%" sind ebenfalls erlaubt. Zahlen ohne Maßeinheit, wie "70" werden jedoch im Browser möglicherweise fehlerhaft dargestellt.
Die Angaben beziehen sich nicht auf die gesamte Größe des Vorschaufensters, sondern sinnigerweise auf den darin dargestellten Text. Die folgende Abbildung demonstriert dies:
Abbildung: Darstellung der Randbereiche
Der hier lila gefärbte Bereich ist der, dessen Größe über die Attribute "width" und "height" festgelegt wird. Der hellgrüne Bereich ist die Gesamtgröße des Feldes. Der Platz, welcher für die Überschrift benötigt wird, ist hellblau dargestellt. Der Rahmen ist hier violett angedeutet. Die Gesamtgröße des Fensters richtet sich also nach den Werten der Attribute "width" und "height", zuzüglich der Überschrift, des Rahmens (border) und des Randbereichs (margin) des Fensters.
[%printArray value="<array>" %]
Attribut | Typ | erforderlich | Defaultwert | Beschreibung |
---|---|---|---|---|
value | array | ja | - | ein Array, welches als String ausgegeben werden soll |
Diese Funktion wandelt ein (eventuell mehrdimensionales) Array in einen String um und gibt diesen aus. Das Array wird im SML-Format dargestellt. Dies kann unter anderem für das Debugging von Templates interessant sein, um herauszufinden welchen Namen eine gesuchte Variable hat.
Hinweis: Ab
Version 2.9.3 des Yana Frameworks unterstützt diese Funktion
Syntaxhervorhebung bei der Ausgabe.
[%printArray value=$LANGUAGE%]
Abbildung: kurzer Auszug aus der Ausgabe
[%printUnorderedList value="<array>" [ keys_as_href="<bool>" ] [ layout="<int>" ] %]
Attribut | Typ | erforderlich | Defaultwert | Beschreibung |
---|---|---|---|---|
value | array | ja | - | ein Array, welches als Liste ausgegeben werden soll |
keys_as_href | bool | nein | false | gibt an, ob Links erzeugt werden sollen |
layout | int | nein | 1 | lässt Sie zwischen 3 alternativen Layouts (1, 2 und 3) für Ihr Menü wählen |
Diese Funktion wandelt ein (eventuell mehrdimensionales) Array in eine unsortierte Liste im HTML-Format um und gibt diese aus. Es wird der Tag "ul" verwendet.
Man kann diese Funktion verwenden, um Baummenüs zu erzeugen. Wahlweise können in diesem Menü Links erzeugt werden. Dazu verwenden Sie bitte die URLs als Schlüssel des Arrays und die Beschriftung als Werte. Außerdem setzen Sie den Parameter "keys_as_href" auf "true".
[%printUnorderedList value=$LANGUAGE%]
Abbildung: kurzer Auszug aus der Ausgabe
2. Beispiel – ein Baummenü mit Links ausgeben:
<?php $A = array( '1.html' => 'Link', 'Menü 1' => array( '2_1.html' => '1. Eintrag', '2_2.html' => '2. Eintrag', 'Menü 2' => array( '2_3_1.html' => '1. Eintrag', '2_3_2.html' => '2. Eintrag' ), ), 'Menü 3' => array( '3_1.html' => '1. Eintrag', '3_2.html' => '2. Eintrag', '3_2.html' => '3. Eintrag' ), ); $YANA->setVar('A', $A); ?>
[%printUnorderedList value=$A keys_as_href="true"%]
Abbildung: Darstellung als Baummenü mit Links
3. Beispiel – weitere Layouts:
[%printUnorderedList value=$A layout=2 keys_as_href="true"%]
Abbildung: Darstellung als vertikales Baummenü
[%printUnorderedList value=$A layout=3 keys_as_href="true"%]
Abbildung: Darstellung als horizontales Baummenü
Die Schlüssel werden fett gedruckt und die Werte kursiv - dies lässt sich jedoch per CSS ändern. Es werden folgende CSS-Klassen verwendet:
[%rss [ image="<string>" ] %]
Attribut | Typ | erforderlich | Defaultwert | Beschreibung |
---|---|---|---|---|
image | string | nein | - | das Icon, auf welches der Besucher klicken kann um den RSS-Feed zu sehen. |
Diese Funktion erzeugt Hyperlinks, zu den verfügbaren RSS-Feeds einer Webseite.
Das Argument "image" kann verwendet werden, um ein Icon auszuwählen. Klickt der Nutzer auf diesen Link, so wird die entsprechende Datei geöffnet. Die Liste der RSS-Feeds wird im Quellcode der Anwendung erzeugt. Siehe dazu auch das Kochbuch für Entwickler, Kapitel: "Sonstige Funktionen".
Tipp: Auch wenn
Sie die Hyperlinks nicht erzeugen, können Ihre Besucher die verfügbaren
RSS-Feeds Ihrer Webseite trotzdem lesen, weil diese Links zusätzlich im
Header der Datei zu finden sind. Diese Informationen kann der Browser
des Besuchers, sofern er dazu in der Lage ist, verwenden, um Ihrem
Besucher das Lesen der Feeds zu ermöglichen. Diese Variante ist für
Ihre Gäste allerdings umständlicher und sollte daher vermieden werden.
[%rss%]
Abbildung: Ausgabe der Funktion
Beispiel – einen Feed zur Ausgabe hinzufügen:
<?php // Der Wert 'mein_rss' ist der Name der Funktion, welche den RSS-Feed ausgibt RSS::publish('mein_rss'); ?>
Hinweis: In den
mitgelieferten Skins werden die Hyperlinks auf vorhandene RSS-Feeds
automatisch erzeugt, so dass Sie diese Funktion in der Regel nicht
selbst benötigen, außer wenn Sie einen eigenen Skin schreiben. In
diesem Fall sollten Sie die Hyperlinks in den Kopfbereich der Seite
einbinden, wo diese für Besucher leicht zugänglich sind.
[%sizeOf value="<mixed>" [ assign="<string>" ] %]
Attribut | Typ | erforderlich | Defaultwert | Beschreibung |
---|---|---|---|---|
value | mixed | ja | - | skalarer Wert oder Array, dessen Länge bestimmt werden soll |
assign | string | nein | - | Name der Template-Variable in welcher das Ergebnis zu speichern ist |
Die Funktion "sizeOf" gibt die Länge eines Arrays oder Strings als Zahl zurück. Falls der Parameter "assign" angegeben wird, so wird der Rückgabewert in der Variable mit diesem Namen gespeichert und die Funktion liefert kein Ergebnis zurück.
<td colspan="[%sizeOf value=$cols%]"> ... </td>
[%sizeOf value=$cols assign="foo"%] <td colspan="[%$foo%]"> ... </td>
[%smilies [ width="<integer>" ] %]
Attribut | Typ | erforderlich | Defaultwert | Beschreibung |
---|---|---|---|---|
width | integer | nein | 1 | Anzahl der Spalten der Tabelle |
Die Funktion "smilies" generiert automatisch eine Tabelle aller verfügbaren Emoticons / Smilies, mit einem Link zum Einfügen in das angegebene Eingabefeld.
<textarea id="text"></textarea>
[%smilies width="5"%]
Abbildung: Darstellung der Smilies (5 pro Zeile)
[%smlLoad file="<string>" [ section="string" ] [ scope="string" ] %]
Attribut | Typ | erforderlich | Defaultwert | Beschreibung |
---|---|---|---|---|
file | string | ja | - | Anzahl der Spalten der Tabelle |
section | string | nein | - | ID eines Input- oder Textarea-Tags |
scope | string | nein | local | gültige Werte: "local", "global", "parent", "template_vars" |
Diese Funktion bietet die gleiche Schnittstelle wie die Smarty-Funktion "config_load". Allerdings arbeitet diese Funktion mit SML-Dateien mit den Dateiendungen "*.sml", "*.cfg" oder "*.config".
Anders als die herkömmlichen Konfigurationsdateien der Smarty-Engine, dürfen SML-Dateien mehrdimensionale Array-Definitionen enthalten.
Außerdem darf das Argument "scope" den Wert "template_vars" besitzen, welcher bewirkt, dass die Variablen der SML-Datei als Templatevariablen verwendet werden - damit ist es möglich auf mehrdimensionale Arrays in gewohnter Weise zuzugreifen. Dieses Feature gibt es nur für smlLoad() und nicht für config_load().
Im Verzeichnis "skins/.config" liegt die Datei "foo.sml". Sie hat folgenden Inhalt:
<TEST>
<A>1</A>
<B>
<C>2</C>
</B>
</TEST>
Im Template steht:
[%smlLoad file="foo.sml" section="TEST.B" scope="template_vars"%]
[%$C%]
Ausgabe: 2
[%smlLoad file="foo.sml" section="TEST.B"%]
[%#C#%]
Ausgabe: 2
[%smlLoad file="foo.sml" scope="template_vars"%]
[%$TEST.B.C%]
Ausgabe: 2
Der Funktionsname "sml_load" ist ein Alias für die Funktion "smlLoad". Sie können beide Bezeichnungen alternativ verwenden.
Zur Beschreibung dieser Funktion.
[%varDump var="<mixed>" %]
Hinweis:
Diese Funktion dient ausschließlich dem Debugging. Sie steht nur zur Verfügung,
wenn das Framework im Debugmodus betrieben wird. Ist dieser Modus deaktiviert,
wird beim Versuch die Funktion aufzurufen ein Fehler erzeugt. Dies dient der
Sicherheit Ihrer Anwendung.
Attribut | Typ | erforderlich | Defaultwert | Beschreibung |
---|---|---|---|---|
var | mixed | ja | - | Wert der ausgegeben werden soll |
Die Funktion "varDump" gibt den Inhalt einer Variablen aus.
[%varDump value=$INSTALLED_LANGUAGES%]
array ( 'de' => 1, 'en' => 1 )
[%$foo|css%]
Erstellt eine Verknüpfung mit dem angegebenen Pfad einer CSS-Datei.
[%"default.css"|css%]
wird umgesetzt zu:
<link rel="stylesheet" type="text/css" href="default.css">
[%$foo|date%]
Erzeugt aus einer Variable, welche einen UTC enthält, eine JavaScript-Anweisung, welche die passende Zeitangabe entsprechend der Zeitzone des Client-Browsers als Text ausgibt.
Template wurde erzeugt am: [%$CTIME|date%]<br>
Template wurde zuletzt bearbeitet am: [%$MTIME|date%]<br>
Template wurde zuletzt aufgerufen am: [%$ATIME|date%]<br>
wird umgesetzt zu:
Template wurde erzeugt am: 1.12.2006
Template wurde zuletzt bearbeitet am: 19.1.2007
Template wurde zuletzt aufgerufen am: 21.1.2007
[%$foo|embeddedTags%]
Ersetzt in einer Variablen vom Typ String Tags gemäß der für YANA vorgegebenen Syntax.
$foo = "Text [b]Text[/b] Text"
wird umgesetzt zu:
Text <span style="font-weight: bold;">Text</span> Text
[%$foo|href%]
Generiert einen Link auf die Datei index.php inklusive aller
erforderlichen Parameter. Der String $foo wird an das Ende des
Search-Strings der URL angehängt. Um die URL werden automatisch
doppelte Anführungszeichen (") erzeugt.
<a href=[%"action=meinplugin_new_entry"|href%]>Neuer Eintrag</a>
wird umgesetzt zu:
<a href="index.php?sessid=foo&id=beispiel&action=meinplugin_new_entry">Neuer Eintrag</a>
[%$foo|smilies%]
Ersetzt in einer Variable vom Typ String enthaltene Codes durch die dazu passenden Icons.
$foo = "Text :example: Text"
[%$foo|smilies%]
wird umgesetzt zu:
Text
<img border="0" hspace="2"
src="common_files/smilies/example.gif">
Text
[%$foo|url%]
Generiert ebenso wie der Modifier "href" einen Link, allerdings als absoluten Pfad und ohne Anführungszeichen zu erzeugen.
<meta http-equiv="Refresh" content="2; URL=[%"action=meinplugin_new_entry"|url%]">
wird umgesetzt zu:
<meta http-equiv="Refresh" content="2;
URL=http://.../index.php?sessid=foo&id=beispiel&action=meinplugin_new_entry">
Achtung!
Folgendes funktioniert nicht:
<a
href="[%"action=foo"|url%]">link</a>
Ergebnis: <a
href="skins/default/http://.../index.php?...">link</a>
[%$foo|urlEncode%]
Kodiert einen Text so, dass er sicher als Parameter in einer
URL verwendet werden kann. Dazu wird die PHP-Funktion urlencode()
verwendet.
<a href="?bar1=foo1&bar2=[%$foo|urlEncode%]">
wird umgesetzt zu:
<a href="?bar1=foo1&bar2=foo%20bar">
Im Yana Framework werden alle Webanwendungen als "Plugins" bezeichnet. Komplexere Anwendungen können aus mehreren Subsystemen bestehen. Diese Subsysteme sind jeweils verschiedene Plugins, die Hand in Hand arbeiten. Einige dieser "Subsysteme" sind bereits vorbereitet implementiert und müssen lediglich verwendet werden.
Auf diese Weise bleiben dem Programmierer viele Arbeiten erspart. Sie müssen sich beispielsweise keine Sorgen um die Passwortabfrage machen. Es gibt bereits Plugins, welche das zuverlässig für Sie erledigen. Auch das Administrationsmenü müssen sie nicht neu schreiben, sondern es einfach nur verwenden. Falls eine Komponente nicht gefällt, kann sie ausgetauscht oder entfernt werden. Falls eine Funktion fehlt, kann sie hinzugefügt werden, ohne andere Plugins verändern zu müssen.
Das Schreiben eines neuen Plugins wird einfacher unter Verwendung des YANA-SDK. Dabei handelt es sich um einen Assistenten, welcher alle erforderlichen Informationen abfragt und dann vollautomatisch eine neue Anwendung für Sie erstellt. Diese müssen Sie lediglich noch Ihren Bedürfnissen anpassen.
Vorbereitend müssen zunächst allgemeine Informationen gegeben werden. Siehe Abbildung oben.
Einige Informationen zu Ihrer Person:
Der zweite Schritt erlaubt dem Entwickler eigene Aktionen zur die Schnittstelle hinzuzufügen.
Falls Sie nur eine einfache Datenbankanwendung erstellen wollen, können Sie diesen Schritt übergehen. Die meisten Standardaktionen, wie das Anzeigen von Datenbankeinträgen, Suche, Editieren, Löschen oder Einfügen, müssen nicht von Hand geschrieben werden. Diese Aktionen erzeugt das SDK automatisch.
Wenn Sie andere Aktionen festlegen möchten, können Sie hier deren Schnittstelle definieren. Dazu können Vorlagen verwendet werden, welche das SDK vorgibt. Ein händische Erstellung ist ebenfalls möglich. Die Schnittstellen können auch nachträglich von Hand verändert werden.
Für einige Standardaktionen gibt es Vorlagen, welche benutzt werden können. Schauen Sie in die Auswahlliste. Wenn eine Option ausgewählt wurde, erscheint zum Vergleich eine Liste der erzeugten Aktionen. Sie können sich die gesamte Schnittstelle anschauen, indem Sie die Option "Schnittstelle von Hand nachbearbeiten" auswählen.
Eine Schnittstelle enthält folgende Informationen:
Diese Option dient zur Kontrolle, beziehungsweise als Alternative Eingabeoberfläche für erfahrene Nutzer. Sie sehen alle definierten Aktionen und können Änderungen vornehmen.
Vorsicht! Fehler können dazu führen, dass das Plugin nicht korrekt erzeugt werden kann.
Es kann für Datenbankanwendungen automatisch eine GUI generiert werden. Dazu wird eine Strukturdatei benötigt, welche die Datenbank beschreibt. Aus den Informationen dieser Datei erzeugt das SDK für jede Tabelle automatisch passende Template-Dateien, sowie die dazu passenden Aktionen und erzeugt zudem die erforderlichen Ergänzungen für die Schnittstelle der Anwendung.
Wenn Sie keine solche Datenbankanwendung erstellen wollen, kann dieser Schritt übergangen werden.
Automatisch erzeugt werden jeweils: pro Tabelle ein Template zum Anzeigen, Editieren, Anlegen und Durchsuchen von Datenbankinhalten, sowie der PHP-Code für die dazu gehörende Aktionen. Außerdem Aktionen, für den Download von Dateien und Bildern aus der Datenbank. Weiterhin wird eine JavaScript-Datei erzeugt, um über Ajax Aktionen auf dem Server auslösen zu können. Zuletzt wird die Strukturdatei selbst im System gespeichert.
Sollten Sie noch keine Strukturdatei geschrieben haben, können Sie eine solche Datei erzeugen. Benutzen Sie dazu das Plugin "DB-Tools". Öffnen Sie das im Administrationsmenü "DB-Tools" / "Import". Wählen Sie eine der Optionen, um eine bereits existierende Datenbank zu importieren. Falls Sie bis jetzt noch keinerlei Vorlage für die Datenbank zur Verfügung haben, lesen Sie bitte das Einführungstutorial. Beachten Sie auch die Beispiele im Kochbuch für Entwickler.
Wenn Sie eine Strukturdatei erzeugt, oder von Hand geschrieben haben, geben Sie bitte hier den Pfad dieser Datei an. Klicken Sie auf "Durchsuchen", wenn Sie sich nicht sicher sind, wo sich diese befindet.
Wählen Sie die Quelldatei im SQL-Format aus, welche die Informationen zur Installation der Datenbank enthält.
Ihre SQL-Installationsdateien finden Sie nach der Generierung des Plugins im Verzeichnis "config/db/.install/". Dieses enthält für jedes unterstützte DBMS Unterverzeichnisse. Hierher können Sie auch nachträglich noch SQL-Dateien von Hand kopieren. Die Datei muss den gleichen Namen haben wie die Strukturdatei und die Endung ".sql" besitzen.
Zum Abschließen der Konfiguration klicken Sie bitte auf die Schaltfläche "Fertigstellen".
Das SDK produziert als Ausgabe ein Skelett der Anwendung, alle erforderlichen Templates, sowie alle notwendigen Konfigurationsdateien. Diese beinhalten insbesondere: Meta-Informationen des Plugins inklusive Beschreibung der Schnittstelle, Meta-Informationen der verwendeten Dateien, Meta-Informationen der verwendeten Templates.
Das soeben generierte Plugin ist sofort lauffähig. Sie finden die entsprechenden Dateien im Verzeichnis "plugins" beziehungsweise "skins/default", unter der ID-Kennung des Plugins.
Um das soeben erzeugte Plugin zu testen:
Diese Anwendung benutzt Dateien zum Speichern von Inhalten, die in mehrere Sprache übersetzt werden können. Diese Dateien sind als Pakete zusammengefasst. Jeweils ein Paket passt genau zu einer Übersetzung. Also beispielweise ein deutsches, oder ein englisches Paket. Jedes Paket enthält Texte und Grafiken. Die in den Textdateien beschriebenen IDs sind Texten zugeordnet. Die IDs entsprechen exakt den dazu passenden Token in den Skinpaketen.
Wenn Sie einen Fehler in einem Übersetzungspaket gefunden haben und korrigieren wollen, finden Sie die entsprechenden Dateien im Verzeichnis "languages/". Jeweils ein Unterverzeichnis pro Paket. Jedes der Pakete enthält Dateien, welche passend den Plugins benannt sind, für die sie bestimmt sind.
Das Editieren der Dateien ist möglichst einfach gestaltet. Öffnen Sie die Datei in einem Texteditor Ihrer Wahl. Die Dateien sind in einem XML-ähnlichen Format geschrieben. Vermeiden Sie die Verwendung von HTML-Tags in diesen Dokumenten. Das Benutzen von Embedded Tags ist erlaubt. Beachten Sie, dass keine Zeilenumbrüche innerhalb des Fließtextes gestattet sind. Um einen Zeilenumbruch einzufügen, benutzen Sie den Emb. Tag [br].
Wenn Sie Übersetzungen editieren empfiehlt es sich, nicht die Originaldaten zu überschreiben. Machen Sie stattdessen eine Kopie der Dateien als neues Sprachpaket.
Um die Textmeldungen der Anwendung in eine neue Sprache zu übersetzen, Speichern Sie eine Kopie des Verzeichnisses "languages/de" und der zugehörigen Konfigurationsdatei "deutsch.config" unter einem neuen Namen. Sinnvollerweise passend zur Sprache, für welche die Übersetzung bestimmt ist. Beispielsweise "languages/es".
Sie haben die Möglichkeit Ihre persönlichen Informationen, wie Name des Autors, oder eine kurze Beschreibung unterzubringen. Editieren Sie diese Einstellungen in der Konfigurationsdatei des Sprachpakets. Außerdem können Sie eine passende Grafik einfügen. Üblicherweise eine Landesflagge. Ersetzen Sie dazu die Datei "flagge.gif". Den Namen der Datei legen Sie in der Konfigurationsdatei unter der ID "LANGUAGE_INFO.LOGO" fest.
"Coding principles" sind grundsätzliche Regeln zum Schreiben und Formatieren von PHP-Code. Die Einhalt dieser Regeln hilft, Quellcode einheitlich, lesbar und übersichtlich zu halten.
Verschiedene Autoren die gemeinsam den gleichen Quellcode bearbeiten, haben oft gegensätzliche Auffassungen davon, wie gut lesbarer Code aussehen sollte. Um dennoch eine einheitliche Schreibweise und gleichbleibende Qualität sicherzustellen ist es notwendig, sich auf die Einhaltung gemeinsamer Regeln zu einigen. Es darf nicht möglich sein von der Formatierung des Quellcodes auf den Autor zu schließen.
Alle Skripte müssen die Dateiendung *.php benutzen und müssen in UTF-8 kodiert sein. Zeilenumbrüche müssen das Linux-Format benutzen (LF statt CRLF oder CR).
Verwenden Sie für Skript-Tags die Schreibweise <?php ... ?> mit schließendem Tag am Ende der Datei. Short-Tags (<? ... ?>) und andere Schreibweisen sind nicht gestattet.
Der geschriebene Code darf bei aktiviertem Error-Reporting keine E_WARNING oder E_NOTICE verursachen. Setzen Sie zum Testen "error_reporting(E_ALL);".
Eine Zeile Quellcode sollte nicht länger als 120 Zeichen sein.
Der Quellcode sollte mit 4 Leerzeichen eingerückt werden. Verwenden Sie keine Tabulatoren.
Für Kommentare verwenden Sie für mehrzeilie Kommentare stets /* comment */. Für einzilige Kommentare // comment. Nicht gestatttet ist die Verwendung von # comment. Alle Kommentare müssen auf Englisch geschrieben werden.
Im Folgenden ein Beispiel:
<?php /* multi-line * comment */ function foo() { // single-line comment foreach ($input as $key => $element) { $element = strip_tags( (string) $element); if (preg_match("/\//", $key)) { $key = preg_replace("/\//", ".", $key); Hashtable::set($output, $key, $element); } else { $output[$key] = $element; } } // end foreach } ?>
Variablen müssen auf Englisch und in CamelCase benannt werden - also $debugSourcePath anstatt $debug_source_path. Der erste Buchstabe wird klein geschrieben.
Viele typische Fehler in PHP rühren daher, dass Programmierer annehmen, eine Variable sei unbenutzt, von einem bestimmten Typ, oder würde an nach einer bestimmten Code-Zeile nicht mehr verwendet. Beachten Sie: eine Variable immer so spät wie möglich deklarieren und so früh wie möglich löschen. Variablen müssen stets initialisiert werden.
<?php // Beginn der Lebensdauer assert('!isset($variable); // Cannot redeclare $variable'); $variable = 0; // ... // Wird die Variable nicht mehr benötigt, sollte sie explizit gelöscht werden unset($variable); // Ende der Lebensdauer ?>
Die Verwendung von Klammern { } ist obligatorisch, selbst in Fällen wo diese technisch nur optional ist. Verwenden Sie zur besseren Lesbarkeit Leerzeichen zwishen den Vergleichsoperatoren.
<?php if ($test1 === 1) { $command1; } elseif ($test2 === 2 || $test === 3) { $command2; } else { $commandN; } // end if ?>
Falls Sie die Klasse "Exception" abfangen wollen, so muss dies der letzte Catch-Block der Anweisung sein.
<?php try { $command1; } catch (FooException $e) { $command2; } catch (BarException $e) { $command3; } catch (Exception $e) { $commandN; } ?>
Beachten Sie für die Switch-Anweisung die Einrückung und die Zeilenumbrüche, diese dienen der Lesbarkeit.
Alle Case-Anweisungen müssen mit einer Break-Anweisung geschlossen werden. Ausnahmefälle müssen ausdrücklich mit dem Kommentar "// fall through" anstatt "break" dokumentiert werden.
Der Default-Statement ist obligatorisch und darf nicht fehlen, selbst wenn es leer ist.
<?php switch ($variable) { case 1: $command1; break; case 2: case 3: $command2; break; case 4: $command4; // fall through default: $commandN; break; } // end switch ?>
Achten Sie auf die Zeilenumbrüche, diese dienen der Lesbarkeit.
Prüfen Sie vor der Schleife unbedingt ob die verwendeten Schleifenvariablen bereits benutzt sind, da PHP diese sonst überschreibt. Löschen Sie Schleifenvariablen nach Verwendung mit unset().
<?php assert('!isset($i); // Cannot redeclare $i'); for ($i = 0; $i < sizeOf($input); $i++) { $command1; } // end for unset($i); assert('!isset($key); // Cannot redeclare $key'); assert('!isset($element); // Cannot redeclare $element'); foreach ($input as $key => $element) { $command2; } // end foreach unset($key, $element); while ($test) { $command3; } // end while ?>
Verwenden Sie CamelCase-Schreibweise. Der erste Buchstabe muss bei Funktionen klein, und bei Klassen groß geschrieben werden.
Die Namen von privaten Funktionen müssen mit einem Unterstrich beginnen. Die Namen privater Variablen dürfen (müssen jedoch nicht) ebenfalls mit einem Unterstrich beginnen. In allen anderen Fällen muss der Name immer mit einem Buchstaben (a-z) beginnen.
Empfehlung: der Namen einer Funktion sollte aus einem Verb und einem Substantiv bestehen, z.Bsp.: "getBeer()" oder "setContent()". Ist der Rückgabewert ein Array, so verwenden Sie den Plural, z.Bsp.: "getLines()".
Zur Dokumentation von Klassen und Funktionen muss PHP-Doc (http://www.phpdoc.org/) verwendet werden.
Die Tags @param, @return, @var und @package sind Pflicht. Dokumentation muss in Englisch verfasst sein.
Vermeiden Sie es Variablen als "public" zu kennzeichnen. Verwenden Sie stattdessen Zugriffsfunktionen ("Getter" und "Setter").
<?php /** * <<Stereotype>> name * * The purpose of this class is ... * * @access public * @package package * @subpackage subpackage */ class MyClass extends BaseClass implements Foo, Bar { /** * Short description * * @access private * @var string */ private $var0 = ""; /**#@+ * Block-declaration * * @access private */ /** @var array */ private $var1 = array(); /** @var int */ private $var2 = 0; /** @var View */ private $var3 = null; /** @var array */ private $var4 = array(); /** @var array */ private $var5 = array(); /**#@-*/ /** * Constructor * * Long description. * * @access public * @param string $filename path to file.ext */ public function __construct($filename) { assert('is_string($filename); // Wrong type for argument 1. String expected'); $command1; } /** * Short description * * Long description. * * @access public * @param string $id alpha-numeric, unique identifier * @return int */ public function getVar($filename) { assert('is_string($filename); // Wrong type for argument 1. String expected'); // ... assert('is_int($result); // Wrong result type. Integer expected'); return $result; } } ?>
Die API-Dokumentation enthält Informationen für Entwickler, die eigene Erweiterungen schreiben wollen. Hier finden Sie Beschreibungen zu Schnittstellen und Beispiele zu allen verfügbaren Klassen und Funktionen der Software.
Das Yana-Framework bietet eine API zum Arbeiten mit Datenbanken, welche auf PEAR-DB basiert. Diese API erweitert die Fähigkeiten von PEAR um folgende Features:
Es gibt einige Features welche die FlatFile-Datenbank zur Zeit nicht unterstützt, die aber für eine zukünftige Version geplant sind.
Es gibt einige Features welche in Datenbankschemata zur Zeit nicht unterstützt werden, aber für zukünftige Versionen geplant sind.
Voraussetzung ist eine Schemadatei. Die Schemadateien müssen sich im Verzeichnis "config/db/" befinden und die Dateiendung ".config" besitzen.
<?php global $YANA; $name_der_strukturdatei = "guestbook"; $datenbankverbdinung = $YANA->connect($name_der_strukturdatei); ?>
Die Verbindungsdaten für die Datenbank (wie Hostadresse, Nutzername und Passwort) werden vom Nutzer im Administrationsmenü eingegeben. Sie müssen diese im Quellcode NICHT angeben.
Wenn Sie keine Strukturdatei verwenden möchten, können Sie diese Angabe frei lassen. Dies wird jedoch in einer Produktionsumgebung nicht empfohlen. In diesem Fall wird das Framework versuchen, die Angaben selbst zu ermitteln. Falls dies fehlschlägt ist die Datenbankverbindung nicht nutzbar.
Wenn Sie eine Verbindung mit einer Datenbank herstellen, aber die Verbindungsdaten selbst angeben wollen, dann gehen Sie wie folgt vor:
<?php /* Die Verbindungsdaten werden als assoziatives Array angegeben: */ $verbindungsdaten = array( 'DBMS' => 'mysql', 'HOST' => 'localhost', 'PORT' => 0, 'USERNAME' => 'nutzername', 'PASSWORD' => 'passwort', 'DATABASE' => 'name_der_datenbank' ); /* Um die YANA-API zur Kommunikation mit der Datenbank zu benutzen schreiben Sie: */ $datenbank_server = new DbServer($verbindungsdaten); $yana_api = new DbStream($datenbank_server); /* Um die PEAR-API zur Kommunikation mit der Datenbank zu benutzen schreiben Sie: */ $datenbank_server = new DbServer($verbindungsdaten); $pear_api = $datenbank_server->get(); /* Um die PEAR-API mit den Standardverbindungsdaten zu benutzen schreiben Sie: */ $datenbank_server = new DbServer(); $pear_api = $datenbank_server->get(); ?>
<?php if (YANA_DATABASE_ACTIVE === true) { print "Datenbank ist aktiviert"; } else if (YANA_DATABASE_ACTIVE === false) { print "Datenbank ist NICHT aktiviert"; } ?>
Dazu bietet die API die Funktion $db->get(string $key). Diese führt eine Select-Anfrage auf der Datenbank aus und liefert den Wert an der Stelle zurück, welche mit dem Argument $key angegeben wurde.
<?php global $YANA; $db = $YANA->connect("guestbook"); /* Es gilt folgende Syntax: $db->get( string "$tabelle.$zeile.$spalte", string $where, string $order_by, int $offset, int $limit ); Beispiel: $value = $db->get("table.1.field","row1=wert1,row2=wert2","row1",0,1); erzeugt folgende SQL-Anfrage: SELECT field from table where primary_key = "1" and row1 like '%wert1%' and row2 like '%wert2%' order by row1 limit 1; */ /* Feld ausgeben */ $value = $db->get("table.1.field"); /* erzeugt folgende SQL-Anfrage: SELECT field from table where primary_key = "1"; */ /* Spalte ausgeben: */ $column = $db->get("table.*.field"); foreach ($column as $row => $value) { print "<p>Value of 'field' in row '$row' = $value</p>"; } /* erzeugt folgende SQL-Anfrage: SELECT field from table; */ /* Zeile ausgeben: */ $row = $db->get("table.2"); foreach ($row as $column => $value) { echo "<p>Value of column '$column' in row '2' = $value</p>"; } /* erzeugt folgende SQL-Anfrage: SELECT * from table where primary_key = "2"; */ /* Tabelle ausgeben: */ $table = $db->get("table"); foreach ($table as $index => $row) { foreach ($row as $column => $value) { echo "<p>Value at 'table.$index.$column' = $value</p>"; } } /* erzeugt folgende SQL-Anfrage: SELECT * from table; */ ?>
Dazu verwenden Sie die Funktion $db->insert($key,$value). Diese fügt den Wert "value" an der Stelle "key" ein. Dabei kann es sich entweder um eine Zeile oder eine Tabellenzelle handeln. Das Einfügen von ganzen Tabellen oder Spalten ist nicht möglich.
Beim ersten Aufruf der Funktion wird automatisch eine Transaktion gestartet. Benutzen Sie die Funktion $db->write() um ein COMMIT der Daten auszulösen. Wenn eine der Anweisungen in der Transaktion fehlschlägt, wird automatisch ein CALLBACK ausgeführt.
Falls die Zeile nicht existiert, wird ein die SQL-Anweisung "insert" benutzt, sonst "update".
Die Funktion gibt bei Erfolg "true" zurück und "false" sonst.
Bitte beachten Sie: die SQL-Anweisung wird erst ausgeführt, wenn die Funktion $db->write() aufgerufen wird.
Im Folgenden einige Beispiele:
<?php global $YANA; $db = $YANA->connect("guestbook"); /* Neue Zeile einfügen: */ $db->insert("table.*",array("row1"=>"wert1","row2"=>"wert2")); $db->write(); /* Zeile aktualisieren: */ $db->insert("table.2",array("row1"=>"wert1","row2"=>"wert2")); $db->write(); /* Zelle aktualisieren: */ $db->insert("table.2.row1","wert1"); $db->write(); /* Transaktion durchführen: */ $db->insert("table.*",array("row1"=>"wert1","row2"=>"wert2")); $db->insert("table.*",array("row1"=>"wert3","row2"=>"wert4")); $db->insert("table.1.row3","wert1"); $db->write(); ?>
Dazu verwenden Sie die Funktion $db->remove($key). Diese löscht den Datensatz an der Adresse "key" aus der Tabelle. Die Funktion gibt bei Erfolg "true" zurück und "false" sonst. Es können nur Datensätze gelöscht werden. Keine Tabellen, Zellen oder Spalten.
Beachten Sie folgende Beschränkung: aus Sicherheitsgründen wird pro Aufruf stets maximal 1 Datensatz gelöscht. Wenn Sie mehrere Datensätze löschen wollen, müssen Sie die Funktion mehrmals aufrufen. Diese Einschränkung soll verhindern, dass jemand durch Unachtsamkeit oder aus einem Versehen eine gesamte Tabelle löschen kann.
Bitte beachten Sie: die SQL-Anweisung wird erst ausgeführt, wenn die Funktion $db->write() aufgerufen wird.
<?php global $YANA;
$db = $YANA->connect("guestbook"); /* Die zweite Zeile löschen: */ $db->remove("table.2"); $db->write(); /** * erzeugt folgende SQL-Anfrage: * DELETE FROM table WHERE primary_key = "2" LIMIT 1; */ /* Die ganze Tabelle "table" löschen: */ for ($i=0; $i < $db->length($table); $i++) { $db->remove("table.*"); } $db->write(); /** * erzeugt folgende SQL-Anfrage: * DELETE FROM table WHERE primary_key = "2" LIMIT 1; */ ?>
<?php global $YANA;
$db = $YANA->connect("guestbook"); if ($db->length("table") === 0) { print "Die Tabelle 'table' ist leer."; } else { print "Die Tabelle 'table' enthält ".$db->length("table")." Datensätze."; } ?>
<?php global $YANA;
$db = $YANA->connect("guestbook"); /* Datenbankverbindung prüfen: */ if ($db->exists() === true) { print "Die Datenbankverbindung ist verfügbar."; } else if ($db->exists() === false) { print "Die Datenbankverbindung ist NICHT verfügbar"; } /* Prüfen ob Tabelle existiert: */ if ($db->exists("table") === true) { print "Die Tabelle 'table' existiert."; } else if ($db->exists("table") === false) { print "Es gibt keine Tabelle mit dem Namen 'table'."; } /* Prüfen ob Datensatz existiert: */ if ($db->exists("table.2") === true) { print "Der Datensatz '2' in der Tabelle 'table' existiert."; } else if ($db->exists("table.2") === false) { print "Es gibt keinen Datensatz '2' in der Tabelle 'table'."; } /* Prüfen ob Feld existiert und einen Wert hat: */ if ($db->exists("table.2.field") === true) { print "Das Feld 'field' im Datensatz '2' in Tabelle 'table' hat einen Wert."; } else if ($db->exists("table.2.field") === false) { print "Das Feld 'field' im Datensatz '2' in Tabelle 'table' existiert nicht oder ist NULL."; } /* Prüfen ob mindestens 1 Feld existiert, dass NOT NULL ist: */ if ($db->exists("table.*.field") === true) { print "Die Spalte 'field' in Tabelle 'table' existiert."; } else if ($db->exists("table.*.field") === false) { print "Die Spalte 'field' in Tabelle 'table' existiert nicht oder alle Werte sind NULL."; } ?>
Das manuelle Erstellen von Installationsroutinen für das Yana Framework ist nicht erforderlich.
Das Yana Framework hat eine generische Installationsroutine für Datenbanken, welche Sie im Administrationsmenü, in der Basiskonfiguration im Menü "Datenbank Setup" finden. Über dieses Menü kann ein Nutzer alle Tabllen installieren oder Inhalte zwischen dem DBMS und der FlatFile-Datenbank synchronisieren.
Abbildung: Herstellen einer Verbindung und Installation von Datenbanken
Die dafür erforderlichen SQL-Anweisungen erstellt das Framework automatisch aus der Strukturdatei Ihrer Datenbank. Der folgende Quellcode zeigt, wie Sie den durch das Framework generierten Code einsehen können.
<?php $db = $YANA->connect('guestbook'); $dbe = new DbExtractor($db); // Erzeugen der "Create Table ..."-Anweisungen für MySQL $sql = $dbe->createMySQL(); // es existieren einige weitere Funktionen für andere DBMS $sql = $dbe->createPostgreSQL(); $sql = $dbe->createMSSQL(); $sql = $dbe->createMSAccess(); $sql = $dbe->createDB2(); $sql = $dbe->createOracleDB(); // Ergebnis ausgeben print implode("\n", $sql); ?>
Falls der generierte Code nicht Ihren Erwartungen entspricht, können Sie diesen durch eine eigene SQL-Datei ersetzen. Kopieren Sie diese bitte in das Verzeichnis "config/db/.install/{DBMS}", wobei Sie statt {DBMS} das Unterverzeichnis wählen, welches dem gewünschten DBMS entspricht. Die Datei "config/db/.install/readme.txt", enthält eine Liste der unterstützten DBMS und der Namen der für diese vorgesehenen Verzeichnisse. Sie müssen nicht für alle DBMS eigene Dateien hinterlegen. Falls eine erforderliche Datei nicht existiert, wird das Framework (wie zuvor) automatisch die notwendigen SQL-Anweisungen selbst erzeugen.
Weitere Details finden Sie in der API-Dokumentation der Klasse: "DbExtractor".
<?php global $YANA; $db = $YANA->connect("guestbook"); $db->importSQL('data.sql'); ?>
<?php global $YANA; $db = $YANA->connect("guestbook"); $csv = $db->toString("table"); file_put_contents("table.csv", $csv); ?>
<?php global $YANA; $db = $YANA->connect("guestbook"); $db->exportStructure("guestbook.config"); ?>
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.
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>
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>
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.
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 | ![]() |
Einzeilige Texte und Zahlen werden beim Editieren der Spalte als Inputfeld dargestellt. Ist die Spalte nicht editierbar, wird der Inhalt als Textzeile dargestellt. |
boolean | ![]() |
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 | ![]() |
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 | ![]() |
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. |
![]() |
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 | ![]() |
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 | ![]() |
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 | ![]() |
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 | ![]() |
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) | ![]() |
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 | ![]() |
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 | ![]() |
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
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.
Nach Klick auf die Schaltfläche werden die geänderten Einstellungen sofort wirksam.
Die Funktion dirlist() liefert für ein Verzeichnis eine sortierte Liste der enthaltenen Dateien und Verzeichnisse als numerisches Datenfeld zurück. Die obligatorischen Verzeichniseinträge "." und ".." werden nicht aufgelistet. Dateien, deren Dateinamen mit dem Zeichen "." beginnen werden ebenfalls nicht aufgelistet. Das betrifft insbesondere Dateinamen wie ".htaccess" oder ".password". Die Dateinamen enthalten keine Pfadangaben. Verzeichnisnamen enthalten keinen abschließenden Querstrich "/".
Der optionale Parameter $filter kann verwendet werden um die Ausgabe auf bestimmte Dateiendungen zu beschränken. Wildcards sind nicht gestattet. Der Dateifilter darf lediglich alphanumerische Zeichen, sowie die Zeichen '.', '-' und '_' enthalten. Andere Zeichen werden beim Aufruf der Funktion automatisch entfernt.
alle Einträge eines Verzeichnisses ausgeben: <?php echo implode("<br>", dirlist("foo/")); ?> Ausgabe: foo1.foo2 foo3.foo2 foo4.foo5 foo6.foo7 alle Einträge mit passender Dateiendung ausgeben: <?php echo implode("<br>", dirlist('foo/', '*.foo2')); ?> Ausgabe: foo1.foo2 foo3.foo2 ... mit mehreren Dateiendungen: <?php echo implode("<br>", dirlist('foo/', '*.foo2|*.foo5')); ?> Ausgabe: foo1.foo2 foo3.foo2 foo4.foo5 objektorientierte Variante: <?php $dirStream = new DirStream("foo/"); $dirStream->read(); $dirlist = $dirStream->dirlist('*.foo2|*.foo5'); echo implode("<br>", $dirlist); /* Hinweis: das Setzen des Dateifilters ist permanent. */ $dirStream->dirlist('*.foo2|*.foo5'); echo $dirStream->length(); /* Ausgabe: 2 */ echo count($dirStream->get()); /* Ausgabe: 2 */ /* Ein erneuter Aufruf von dirlist() setzt den Dateifilter neu */ $dirStream->dirlist(""); echo $dirStream->length(); /* Ausgabe: 4 */ ?>
Die Funktionen $dirStream->create($mode) beziehungsweise $dirStream->delete() sind für Erzeugen beziehungsweise Löschen von Verzeichnissen verantwortlich. Der optionale Parameter $mode kann verwendet werden, um unter LINUX/UNIX -Betriebssystemen Zugriffsrechte von Verzeichnissen festzulegen. Der Defaultwert ist 777.
Beispiele für gültige Werte für $mode finden Sie in der folgenden Tabelle. Dabei steht "r" für "readable", "w" für "writeable" und "x" für "executable".
Besitzer | Gruppe | sonstige Nutzer | Wert |
---|---|---|---|
rwx |
rwx |
rwx |
777 |
rw- |
rw- |
--- |
660 |
rw- |
rw- |
rw- |
666 |
rwx |
r-x |
r-x |
755 |
rwx |
r-x |
--- |
750 |
rwx |
--- |
--- |
700 |
Beispiele für gültige Werte (entsprechend Unix: CHMOD)
<?php $dirStream = new DirStream("foo/"); $dirStream->read(); /* erzeuge das Verzeichnis "foo/" */ $dirStream->create(); /* erzeuge das Verzeichnis "foo/" mit Zugriffsrechten 660 */ $dirStream->create(660); /* Anzahl der Dateien in einem Verzeichnis feststellen */ print "Verzeichnis 'foo/' enthält ".$dirStream->length()." Dateien."; /* lösche das Verzeichnis "foo/" */ $dirStream->delete(); /* lösche das Verzeichnis "foo/" inklusive aller Dateien und Unterverzeichnisse */ $dirStream->delete(true); /* prüfe ob Verzeichnis existiert */ $test = $dirStream->exists(); if ($test === true) { print "Verzeichnis existiert"; } else if ($test === false) { print "Verzeichnis existiert NICHT"; } ?>
Die Funktion SML::getFile() lädt die angegebene Konfigurationsdatei im SML-Format und liefert den Inhalt als PHP-Variable zurück.
<?php /* Lies Inhalte von Datei und gib Inhalte als Array zurück */ $array = SML::getFile("foo.config"); /* Schlüssel in Großbuchstaben */ $array = SML::getFile("foo.config", CASE_UPPER); /* Schlüssel in kleinen Buchstaben */ $array = SML::getFile("foo.config", CASE_LOWER); /* Schlüssel so wie gespeichert (default) */ $array = SML::getFile("foo.config", CASE_MIXED); /* ... oder: */ $array = SML::getFile(file("foo.config")); /* ... oder: */ $array = SML::decode(file_get_contents("foo.config")); /* einen SML-String erzeugen und dekodieren */ $input_array = array(1,2,3,array(4,5),'a'=>6,'B'=>7); $output_array = SML::decode(SML::encode($input_array)); $input_array == $output_array; // true /* objektorientierte Variante, gemischte Schreibweise */ $configFile = new ConfigFile("foo.config"); $configFile->read(); $array = $configFile->get(); /* objektorientierte Variante, Schlüssel in Großbuchstaben */ $smlFile = new SML("foo.config"); $smlFile->read(); $array = $smlFile->get(); ?> Navigieren innerhalb einer SML-Datei: Angenommen die Datei "foo.config" hätte folgenden Inhalt: <ROOT> <FOO1> <FOO2>text</FOO2> <FOO3> <0>1</0> <1>foo</1> </FOO3> </FOO1> </ROOT> <?php $mixed = $smlFile->get("ROOT.FOO1"); print_r($mixed); ?> Diese Abfrage liefert den Teilbaum ROOT.FOO1 mit FOO1 als Wurzelement. Ausgabe: array( "FOO2" => "text", "FOO3" => array ( 0 => 1, 1 => "foo" ) )
Die Funktion SML::encode() erzeugt für die übergebene Variable eine Darstellung als SML-Code und liefert diesen als String zurück. Es muss sich entweder um eine Variable mit einem skalaren Wert oder ein Array handeln.
Bitte beachten Sie: die Funktion "SML::encode" erkennt keine unendlichen Rekursionen. Daher müssen die Datenfelder rekursionsfrei sein. Andernfalls wird durch den Compiler eine Fehlermeldung erzeugt.
Speichert die Einträge eines Array in der Datei "foo.config": <?php $string = SML::encode($array, "ROOT"); file_put_contents("foo.sml", $string); ?> Ersetzen Sie "ROOT" durch den Namen des Wurzelelements! Benutzen von Großbuchstaben, Kleinbuchstaben und gemischter Schreibweise analog zu SML::decode(): <?php $string = SML::encode($array, "ROOT", CASE_UPPER); // groß $string = SML::encode($array, "ROOT", CASE_LOWER); // klein $string = SML::encode($array, "ROOT", CASE_MIXED); // gemischt (default) ?> objektorientierte Variante, gemischte Schreibweise: <?php $configFile = new SML("foo.sml"); $configFile->read(); $configFile->create(); $configFile->insert($string); $configFile->write(); ?> objektorientierte Variante, Schlüssel in Großbuchstaben: <?php $smlFile = new SML("foo.sml", CASE_UPPER); $smlFile->read(); $smlFile->create(); $smlFile->insert($string); $smlFile->write(); ?>
Zum Kopieren einer Datei besitzen alle YANA-Klassen, die Dateien repräsentieren, die Funktion "copy". Beim Kopieren der Datei können außerdem auch deren Zugriffsrechte gesetzt werden. Sollte das Verzeichnis, in welches die Datei kopiert werden soll, noch nicht existieren, kann es automatisch erzeugt werden. Letzteres ist optional.
Im Folgenden einige Beispiele.
eine Datei kopieren: <?php $foo = new SecureFileStream("foo.txt"); $foo->copy("bar.txt"); $foo->copy("bar.txt"); // Fehlermeldung: Datei existiert bereits ?> eine Datei kopieren und bereits existierende Dateien überschreiben: <?php $foo->copy("bar.txt", true); $foo->copy("bar/foo2.txt"); // Fehlermeldung: Verzeichnis 'bar' existiert nicht ?> eine Datei kopieren und fehlende Verzeichnisse automatisch erzeugen: <?php $foo->copy("bar/foo2.txt", false, true); /* Das Verzeichnis 'bar/' wurde angelegt und die Datei 'foo2.txt' darin gespeichert. Die Zugriffsrechte für das Verzeichnis wurden per Default auf 766 gesetzt. */ /* das Verzeichnis wird nun wieder gelöscht */ $dir = new DirStream("bar"); $dir->delete(true); ?> eine Datei kopieren und Zugriffsrechte für die kopierte Datei auf 655 setzen: <?php $foo->copy("bar/foo2.txt", false, false, 655); /* Das Verzeichnis 'bar/' wurde erneut angelegt. Die Zugriffsrechte für das Verzeichnis wurden nun auf 655 gesetzt - so wie für die Datei. */ ?>
Das Framework bietet die Möglichkeit persistente Zählervariablen, also solche deren Wert automatisch gespeichert wird, zu verwenden.
Es gibt zwei Arten von Zählervariablen: solche, die mit IP-Check, welche nur dann zählen, wenn der Nutzer mit der aktuellen IP nicht innerhalb der letzten 3 Stunden eine Veränderung des Zählers bewirkt hat. Und solche ohne IP-Check, welche stets weiter zählen wenn Sie aufgerufen werden.
Im Folgenden einige Beispiele.
<?php /* Erzeuge einen Zähler mit IP-Check */ $counter = new Counter("meine_statistiken", YANA_COUNTER_USE_IP); /* ... oder auch: */ $counter = new Counter("meine_statistiken"); /* Erzeuge einen Zähler ohne IP-Check */ $counter = new Counter("meine_statistiken", YANA_COUNTER_IGNORE_IP); /* Den Zähler "test1" um 1 erhöhen */ $counter->count("test1"); /* Den Zähler "test2" um 1 erhöhen und eine Beschreibung der Änderung speichern */ $counter->count("test2", "Bewertung"); /* Den Zähler "test1" um 3 erhöhen */ $counter->count("test1", "Bewertung", 3); /* Den Zähler "test1" um 2 verringern */ $counter->count("test1", "Bewertung", -2); ?>
<?php $counter = new Counter("meine_statistiken"); /* Den Zählerstand von "test1" abfragen */ $int = $counter->getCount("test1"); /* Die Beschreibung von Zähler "test1" abfragen */ $string = $counter->getInfo("test1"); print $string.":\t".$int; /* Ausgabe Bewertung: 2 */ /* Alle Zähler abfragen */ $array = $counter->getCount("*"); foreach ($array as $a => $b) { print $a.":\t".$b; } ?>
<!-- In der Template-Datei fügen Sie folgendes ein: --> <img src=[%"action=graphic_counter&target=0"|href%]>
Mit dem Parameter "target" wählen Sie die Grafik aus. Gültige Werte sind die Zahlen 0-6.
Wert für Target | Darstellung |
---|---|
0 | ![]() |
1 | ![]() |
2 | ![]() |
3 | ![]() |
4 | ![]() |
5 | ![]() |
6 | ![]() |
Versionsinformation: Die Funktionen send_mail und form_mail, sowie die Klasse form_mailer wurden in Version 2.8 umbenannt in sendMail, formMail und formMailer, um der Namenskonvention des Frameworks zu entsprechen. Die Funktion sendMail ist ab Version 2.8 eine statische Funktion der Klasse Mailer. Die Funktion formMail ist ab Version 2.8 eine statische Funktion der Klasse FormMailer.
Das Framework bietet die Funktion Mailer::mail() zum Versand von Mails. Diese Funktion implementiert eine Reihe von Sicherheitsvorkehrungen, zum Schutz vor verschiedenen Arten von Header-Injection.
Die Funktion "Mailer::mail" ist eine gegen Missbrauch und "Header-Injection" abgesicherte Variante der nativen PHP-Funktion "mail". Anders als "mail" werden alle Eingabedaten geprüft und auch nicht alle Header-Informationen, welche "mail" prinzipiell gestattet sind erlaubt.
Es wird "true" zurückgegeben, wenn die Mail versandt werden konnte, "false" sonst. Der Wert "true" bedeutet jedoch nicht, dass die Mail erfolgreich zugestellt wurde. Er bedeutet lediglich, dass die Eingabedaten im Sinne dieser Funktion syntaktisch korrekt waren.
Die Funktion erzeugt im Header der Mail die zusätzlichen Einträge "x-yana-php-header-protection" und "x-yana-php-spam-protection".
Wenn Sie eine Mail empfangen, die über YANA versendet wurde, können Sie im Header der Mail die entsprechenden Einträge prüfen, um zu sehen ob das Framework im Nachrichtentext Unregelmäßigkeiten entdeckt hat.
Aus Sicherheitsgründen gelten folgende Einschränkungen.
Empfänger:
$recipient
Der Parameter muss eine gültige Mailadresse sein gemäß des regulären
Ausdrucks (Perl-Syntax)
/^[äöüß\w\d-_\.]{1,}\@[äöüß\w\d-_\.]{2,}\.[\w\d-_\.]{2,}$/i
Betreff:
$subject
Alle Sonderzeichen außer "()äÄüÜöÖß[]", alle Tags sowie alle
Zeilenumbrüche werden still (ohne Warnung) entfernt. Bei einer Länge
von mehr als 128 Zeichen werden alle nachfolgenden Zeichen still
entfernt.
Nachrichtentext:
($text)
Alle '@'-Zeichen werden still durch die Zeichenkette "[at]" ersetzt.
Bei Textnachrichten erfolgt ein automatischer Zeilenumbruch nach
spätestens 70 Zeichen. Bei HTML-Nachrichten werden einige potentiell
gefährliche Tags still entfernt (Blacklist-Ansatz).
Header:
$header
Dieser Parameter ist ein assoziatives Datenfeld. Es darf beliebige
X-Header-Daten enthalten, sowie einige unkritische Header-Informationen
(Whitelist-Ansatz).
Parameter | Typ | Default | Beschreibung |
---|---|---|---|
from | - | Eine gültige Mailadresse | |
return-path | - | Eine gültige Mailadresse | |
cc | mixed | - | Entweder eine gültige Mailadresse oder ein numerisches Datenfeld mit mehreren Mailadressen. An alle angegebenen Adressen wird eine Kopie der Nachricht versandt. Anders als bei "bcc" ist die Liste der Empfänger jedoch für alle Empfänger sichtbar. |
content-type | string | text/plain; charset="UTF-8" |
Bestimmt den MIME-Type der Nachricht. Nur MIME-Type und Charset sind als Eingaben erlaubt. Andere Werte werden ignoriert. |
mime-version | float | 1.0 | Angabe muss entsprechend folgendes regulären Ausdrucks erfolgen (Perl-Syntax): /^\d\.\d$/ |
content-transfer-encoding | string | - | Angabe muss entsprechend folgendes regulären Ausdrucks erfolgen (Perl-Syntax): /^\d{,2}bit$/i |
gültige Belegungen für den Parameter $header der Funktion Mailer::mail()
Die Verwendung von "BCC" ist aus Sicherheitsgründen nicht gestattet.
<?php $recipient = "meineMail@domain.tld"; $subject = "Benachrichtigung"; $mailer = new Mailer("skins/mein_skin/beispiel.mail"); $mailer->subject = $subject; $mailer->sender = $ARGS["mail"]; $mailer->insert("NAME", $ARGS["name"]); $mailer->insert("NACHRICHT", $ARGS["nachricht"]); $mailer->insert("IP", $_SERVER["REMOTE_ADDR"]); $test = $mailer->send($recipient); if ($test === true) { print "Versand erfolgreich"; } else if ($test === false) { print "Versand nicht erfolgreich"; } ?>
<?php $recipient = "meineMail@domain.tld"; $subject = "Benachrichtigung"; $mailer = new Mailer("skins/mein_skin/beispiel.mail"); $mailer->subject = $subject; $mailer->sender = $ARGS["mail"]; $mailer->insert("NAME", $ARGS["name"]); $mailer->insert("NACHRICHT", $ARGS["nachricht"]); $mailer->insert("IP", $_SERVER["REMOTE_ADDR"]); $test = $mailer->send($recipient); if ($test === true) { print "Versand erfolgreich"; } else if ($test === false) { print "Versand nicht erfolgreich"; } ?>Eine versandte Mail könnte dann wie folgt aussehen:
Anmerkung: vor dem Versand der E-Mail prüft die Funktion $mailer->send() die Eingabedaten automatisch auf Versuche von Header-Injection und säubert alle Eingaben. Es kann jedoch absolut nichts schaden, wenn Sie die Syntax der Eingabedaten trotzdem auch in Ihrem Skript noch einmal überprüfen bevor Sie die Funktion aufrufen.
<?php $formMailer = new FormMailer(); // Betreff $formMailer->subject = "Benachrichtigung"; // Kopf- und Fusszeile $formMailer->headline = "Inhalte des Kontaktformulars:\n\n" $formMailer->footline = "\n\nYANA formmailer at ".$_SERVER['SERVER_NAME']; // Formularinhalt $formMailer->content = $_POST; $test = $formMailer->send("meineMail@domain.tld"); if ($test === true) { print "Versand erfolgreich"; } else if ($test === false) { print "Versand nicht erfolgreich"; } ?>Eine versandte Mail könnte dann wie folgt aussehen:
Zu diesem Zweck bietet Ihnen YANA die Funktion untaintInput().
Die Funktion verfügt über folgende Parameter:
Parameter |
Typ |
Default |
Beschreibung |
---|---|---|---|
value | mixed | - | zu säuberndes Datum |
type | string | - | Datentyp Neben den von PHP unterstützten nativen Typen sind noch folgende Werte erlaubt:
|
length | integer | 0 | Maximale Länge des Datums |
escape | integer | 0 | siehe Tabelle |
Parameterliste untaintInput
Der Parameter $escape kann mit einer der folgenden Konstanten belegt werden.
Bezeichner | Beschreibung |
---|---|
YANA_ESCAPE_NONE | keine Änderungen durchführen (Default) |
YANA_ESCAPE_SLASHED | wandelt einfache und doppelte Anführungszeichen in ihre entsprechenden Escapesequenzen in C-Syntax um |
YANA_ESCAPE_TOKEN | ersetzt enthaltene Token durch ihre HTML-Entities |
YANA_ESCAPE_CODED | ersetzt HTML-Symbole, beispielsweise Tagklammern, durch Entities |
YANA_ESCAPE_LINEBREAK | wandelt alle Whitespace-Zeichen (insbesondere Zeilenumbrüche) in Leerzeichen um |
YANA_ESCAPE_USERTEXT | zur Behandlung von Text aus Textarea-Feldern |
Gültige Belegungen für den Parameter $escape der Funktion untaintInput
Für INPUT-Felder sollten Sie stets die Funktion untaintInput() mit dem Parameter YANA_ESCAPE_LINEBREAK aufrufen. Das verhindert, dass ein Angreifer Zeilenumbrüche in Ihre Ausgabe schmuggelt. Für TEXTAREA-Felder sollten Sie den Parameter YANA_ESCAPE_USERTEXT verwenden. Dieser verhindert viele Formen von Flooding, indem Zeichenfolgen die sich ständig wiederholen (Copy'n'Paste Flooding) entfernt werden, oder zum Beispiel ellenlange Texte oder Leerzeichen nach einer bestimmten Anzahl von Leerzeichen per Zwang umgebrochen werden, um das Layout Ihrer Seite nicht zu zerstören.
YANA schreibt alle Log-Einträge in eine Tabelle der Datenbank. Dies geschieht jedoch nur, wenn Logging aktiviert ist. Sie können dies deaktivieren, um Speicherplatz zu sparen. Dieses Feature ist nach der Installation per Default deaktiviert.
Abbildung: Optionen, Programmsetup
Abbildung: Protokollierung aktivieren
Abbildung: Liste der Protokolleinträge
<?php global $YANA; /* Einen Text in die Logs schreiben */ $log = new Log("Mein Log-Eintrag"); $YANA->report($log); /* Text und Dump von Daten */ $dump = $irgendwelche_daten; $log = new Log("Mein Log-Eintrag",$dump); $YANA->report($log); /* den erzeugten Log-Eintrag ansehen */ print $log->getLog(); ?>
Durch Aufruf von $YANA->report(Report $report) kann eine Textmeldung erzeugt werden.
Der Parameter $report ist eine Instanz einer der folgenden Klassen. Diese Klassen haben die gemeinsame Oberklasse "Report".
Klasse | Beschreibung |
---|---|
Log | für Ausgabe in Log-Datei |
Message | Erfolgsmeldung (Bildschirm) |
Warning | Warnung |
Alert | Hinweis |
Error | Fehler |
akzeptierte Typen für Parameter $report
Der Konstruktor wird wie folgt aufgerufen:
new Log(string $text [, mixed $data]);
Das folgende Beispiel schreibt eine Meldung in die Log-Datei und erzeugt dann einen Text für die Ausgabe am Bildschirm.
$YANA->report( new Log("IO-ERROR: Unable to read file
$a") );
$YANA->report( new Error('NOT_READABLE', array('FILE' =>
$a) ) );
Der Parameter $text kann ein Error-Code sein, oder auch ein beliebiger Fließtext. Für Bildschirmausgabe sollten Error-Codes verwendet werden. Für Ausgaben in die Log-Datei bietet sich englischer Fließtext an. Der Parameter $data ist optional und enthält weitere Optionen. Beispielsweise den Datensatz, der nicht gespeichert werden konnte, oder den Namen einer Datei, die gerade nicht geöffnet werden kann.
Gültige Error-Codes für den Parameter $text sind unter anderem (AUSZUG):
Code | Beschreibung | Textauszug |
---|---|---|
200 | Erfolg | Änderungen wurden gespeichert. Vielen Dank !!! |
500 | Allgemeiner Fehler | Es ist ein Fehler aufgetreten... |
403 | Fehler: Zugriff verweigert | Passwort erforderlich. Sie betreten einen geschützten Bereich... |
INPUT_INVALID | Fehler: Falsche Eingabe | Ein gewählter Parameter ist ungültig... |
404 | Fehler: Datei nicht gefunden | Bitte überprüfen Sie die angegebene URL und versuchen Sie es erneut. |
ALLREADY_EXISTS | Fehler: Eintrag doppelt | Es konnte kein neuer Eintrag mit der id "%ID%" erzeugt werden, weil bereits ein anderes Eintrag mit diesem Namen existiert. |
FILE_NOT_CREATED | Fehler: IO-Error | Die Datei "%FILE%" konnte nicht erzeugt werden. |
NOT_WRITEABLE | Fehler: IO-Error | Der Schreibzugriff auf die Ressource "%FILE%" ist gescheitert. Daten konnten nicht gespeichert werden. |
NOT_READABLE | Fehler: IO-Error | Der Zugriff auf die Ressource "%FILE%" ist gescheitert. Daten konnten nicht gelesen werden. |
akzeptierte Belegungen für Parameter $text
Enthaltene Token, wie %FILE% werden ersetzt in der folgenden Weise:
<?php $YANA->report( new Warning('FILE_NOT_CREATED', array('FILE' => $a)) ); ?>
Das besondere an $YANA->report() ist, dass Sie damit gleichzeitig Textmeldungen in die Log-Datei schreiben UND Meldungen am Bildschirm ausgeben können. Wird die Methode mehrmals aufgerufen, werden mehrere Textmeldungen erzeugt.
<?php $YANA->report( new Warning('FILE_NOT_CREATED', array('FILE' => $a)) ); /* ... */ $YANA->report( new Alert('NOT_WRITEABLE', array('FILE' => $a)) ); /* ... */ $YANA->report( new Error('500') ); $YANA->report( new Log("Input/Output Error in File $a.", $lost_data) ); return false; ?>
Der Aufruf von Yana->report erzeugt nur die Textmeldung, bricht aber das Programm nicht ab. Um das Programm zu unterbrechen, verwenden Sie die Methode Yana->exitTo. Bitte beachten Sie: verwenden Sie NICHT die PHP-Methoden exit() oder die(). Andernfalls wird keine Ausgabe erzeugt.
Die Methode Yana->exitTo( [string $action] ) kann verwendet werden um das Programm zu unterbrechen und anzugeben, welche Aktion anschließend ausgeführt werden soll. Das heißt, die Verarbeitung der aktuellen Aktion wird abgebrochen und stattdessen wird das Skript mit der Aktion $action fortgesetzt.
Dabei gibt das Framework alle Textmeldungen an den Browser aus und ruft sich selbst erneut auf. Der Parameter $action entspricht dabei dem URL-Parameter "action".
Wenn der Parameter $action nicht angegeben wird, dann wird stattdessen automatisch die Startseite aufgerufen.
Sie können für $action die spezielle Aktion "null" verwenden, falls Sie das Programm beenden möchten OHNE dass mit der Verarbeitung einer anderen Aktion fortgesetzt werden soll.
Im Folgenden ein einfaches Beispiel:
<?php // erzeuge einige Textmeldungen $YANA->report( new Log('Ein Eintrag für die Log-Files') ); $YANA->report( new Alert('NOT_WRITEABLE', array('FILE' => $a)) ); // stoppe die Bearbeitung des Programms und setze es mit der Aktion 'index' fort $YANA->exitTo('index'); // erzeuge eine Fehlermeldung $YANA->report( new Error('Access denied!') ); // Abbruch des Programm (setze NICHT mit anderer Aktion fort) $YANA->exitTo('null'); // Abbruch des Programms und Aufruf der Startseite $YANA->exitTo(); ?>
YANA stellt einen globalen Speicherbereich zur Verfügung, der von allen Plugins gelesen und verändert werden kann. Alle Variablen, die in diesem Bereich gespeichert werden, stehen Ihnen automatisch in allen Skins und Templates für die Ausgabe zur Verfügung. Bitte beachten Sie: der globale Speicherbereich in YANA ist etwas anderes als der global Namespace von PHP.
Innerhalb dieses Speichers werden Werte als ein Baum, in Form von mehrdimensionalen, assoziativen Arrays gespeichert. Der Zugriff auf diesen Speicherbereich erfolgt analog zu Smarty – oder, falls Ihnen der Vergleich besser gefällt, ähnlich wie mit XPath – über einen Schlüssel.
Zum Beispiel:
<?php $array = $YANA->getVar("*"); // mit Hilfe des Schlüssels "*" erhalten Sie eine Kopie des gesamten Arrays $int = $YANA->getVar("a"); // Ausgabe: 2 $array = $YANA->getVar("b"); // Ausgabe: array("c" => 3, 1 => 4) $int = $YANA->getVar("b.c"); // Ausgabe: 3 /* Anders als in XML-Dateien sind hier numerische Ids erlaubt: */ $int = $YANA->getVar("b.1"); // Ausgabe: 4 ?>
Die Funktion $YANA->getVar() erlaubt Ihnen das Lesen von Werten im globalen Speicherbereich.
<?php global $YANA; /* alle Werte lesen */ $array = $YANA->getVar("*"); /* einzelne Werte lesen */ $mixed = $YANA->getVar("FOO1.FOO2.FOO3"); /* alternativ */ $mixed = $YANA->registry->getVar("FOO1.FOO2.FOO3"); ?>
Die Funktion $YANA->setVar() erlaubt Ihnen das Schreiben von Werten in den globalen Speicherbereich.
<?php global $YANA; /* Variable "MEINE_VARIABLE" registrieren */ $bool = $YANA->setVar("MEINE_VARIABLE", $neuer_wert); $bool = $YANA->setVar("FOO1.FOO2.MEINE_VARIABLE", $neuer_wert); /* alternativ */ $mixed = $YANA->registry->setVar("FOO1.FOO2.MEINE_VARIABLE", $neuer_wert); ?>
Dazu bietet YANA die Funktion $YANA->unsetVar(). Ein Beispiel:
<?php global $YANA; /* Variable "MEINE_VARIABLE" löschen */ $bool = $YANA->unsetVar("MEINE_VARIABLE"); $bool = $YANA->unsetVar("FOO1.FOO2.MEINE_VARIABLE"); /* alternativ */ $mixed = $YANA->registry->unsetVar("FOO1.FOO2.MEINE_VARIABLE"); ?>
Dazu bietet YANA die Funktion $YANA->setType(). Ein Beispiel:
<?php global $YANA; /* den Typ der Variable "MEINE_VARIABLE" auf String ändern */ $bool = $YANA->setType("MEINE_VARIABLE", "string"); $bool = $YANA->setType("FOO1.FOO2.MEINE_VARIABLE", "string"); /* alternativ */ $mixed = $YANA->registry->setType("FOO1.FOO2.MEINE_VARIABLE", "string"); ?>
<?php global $YANA; $array = $YANA->getVar("INSTALLED_PLUGINS"); print_r($array); ?>Ausgabe:
Array ( [CONFIG] => 1 [DB_ADMIN] => 1 [DEFAULT_LIBRARY] => 1 [GUESTBOOK] => 1 [GUESTBOOK_ADMIN] => 1 [USER] => 1 )Prüfen ob ein bestimmtes Plugin installiert ist:
<?php $bool = $YANA->getVar("INSTALLED_PLUGINS.MEIN_PLUGIN"); if ($bool) { print "Plugin 'MEIN_PLUGIN' gefunden."; } else { print "Plugin 'MEIN_PLUGIN' nicht gefunden."; } /* alternativ */ $YANA->plugins->isInstalled('MEIN_PLUGIN'); ?>
Das "Website-Profil" wird über den URL-Parameter "id" ausgewählt. Jedes Profil kann individuelle Einstellungen haben. Diese Einstellungen werden ebenfalls im globalen Speicherbereich des Frameworks abgelegt. Wird kein Profil gewählt, dann wird das Profil "default" verwendet. De facto müssen Sie als Programmierer sich nicht darum kümmern, welches Profil gewählt ist. Sie müssen nur wissen, dass in den Profildaten Einstellungen, wie die gewählte Hintergrundfarbe der Seite, die bevorzugte Schriftart und andere interessante Daten gespeichert sind, auf die Sie bei Bedarf zugreifen können.
<?php global $YANA; /* die aktuellen Profileinstellungen lesen und ausgeben */ $array = $YANA->getVar("PROFILE"); print_r($array); ?>
Array ( >> Layout der Website [BGCOLOR] => #F0F0F0 [PFONT] => Arial, Helvetica, sans-serif [BGIMAGE] => [LOGO] => [HSIZE] => [HCOLOR] => [HFONT] => [PSIZE] => [PCOLOR] => >> Gewählte Sprache, Skin und Verzeichnis für Emoticons / Smilies [LANGUAGE] => deutsch.config [SKIN] => default.config [SMILEYDIR] => common_files/smilies/ >> Sonstige Einstellungen [USERMODE] => 1 [AUTO] => 1 [TIMEFORMAT] => 0 >> Protokollierung [LOGGING] => 1 [LOG_LENGTH] => 50 >> Einstellungen für Plugin "rss to html factory" [RSS] => Array ( [FILE] => plugins/rss/test.rss [MAX] => 5 ) >> Einstellungen für Plugin "guestbook" (Gästebuch) [GUESTBOOK] => Array ( [NOREPLY] => noReply@meineAdresse.tld [FLOODING] => 0 [ENTPERPAGE] => 5 [NOTIFICATION] => [SENDMAIL] => [MAIL] => meinName@meineAdresse.tld [FILE] => [SPAMPROTECT] => 1 [PROFILE] => [USE_DB] => ) >> Einstellungen für Plugin "search" (Stichwortsuche) [SEARCH] => Array ( [TARGET] => _self ) >> Einstellungen für Plugin "user_admin" (Nutzerverwaltung) [USER] => Array ( [ALLOW_CREATE] => 0 ) ) <?php /* die gewählte Hintergrundfarbe auslesen */ $string = $YANA->getVar("PROFILE.BGCOLOR"); print '<p style="background-color: '.$string.'">test</p>'; ?>
<?php global $YANA; /* YANA Defaut-Einstellungen ausgeben */ $array = $YANA->getVar("DEFAULT"); print_r($a); ?>Ausgabe:
Array ( >> Legt fest, welche Aktion automatisch aufgerufen werden soll, wenn das Argument "action" leer oder nicht gesetzt ist. Voreingestellt ist "sitemap" - man kann aber z.Bsp. auch "guestbook_read" verwenden für das Gästebuch, oder "search_start" für die Suchmaschine. Diese Einstellung wurde eingeführt in Version 2.8.0 [HOMEPAGE] => sitemap >> Legt fest, ob Textmeldungen (Fehler, Hinweise etc.) in einem eigenen Fenster (true) oder im Text der normalen Seite (false) angezeigt werden sollen. Diese Einstellung wurde eingeführt in Version 2.8.2 [MESSAGE] => false >> Default-Event Konfiguration für Ereignisse, die nicht definiert sind [EVENT] => Array ( [TYPE] => default [MODE] => 0 [PERMISSION] => 0 [TEMPLATE] => index [INSERT] => ) >> Default-Interface Konfiguration [INTERFACE] => Array ( [TEST] => Array ( [TYPE] => private [MODE] => 0 [PERMISSION] => 0 [TEMPLATE] => NULL ) ) >> Default-Skin Konfiguration [SKIN] => Array ( [DIRECTORY] => default/ ) >> Default-Language Konfiguration [LANGUAGE] => Array ( [DIRECTORY] => de/ ) >> Voreingestellung für Datenbankverbindungen [DATABASE] => Array ( [DSN] => Array ( [USE_ODBC] => [DBMS] => mysql [HOST] => localhost [PORT] => 0 [USERNAME] => root [PASSWORD] => [DATABASE] => yana ) >> Konfiguration der Datenbankschnittstelle [OPTIONS] => Array ( [AUTOFREE] => 1 [PERSISTENT] => 1 [SSL] => ) >> Liste der DBMS, welche über die ODBC-Schnittstelle angesprochen werden sollen [REQUIRE_ODBC] => Array ( [0] => db2 [1] => access ) ) )
<?php global $YANA; /* Nutzer IP */ print $YANA->getVar("REMOTE_ADDR")."\n"; /* Nutzer Name */ print $YANA->getVar("SESSION_USER_ID")."\n"; /* Zugriffslevel des Nutzers */ print $YANA->getVar("PERMISSION")."\n"; /* Session-Name */ print $YANA->getVar("SESSION_NAME")."\n"; /* Session-ID */ print $YANA->getVar("SESSION_ID")."\n"; ?> Ausgabe: 127.0.0.1 ADMINISTRATOR 100 YSID 480f97e69eae2311d3157cc3377a2d73
Ein CAPTCHA ist eine Methode zum Schutz vor Spam. Dazu wird eine Grafik mit einem Text angezeigt, welchen der Besucher abtippen muss. Ein Mensch kann das mit Leichtigkeit, ein Spam-Bot hingegen kann das nicht. Auf diese Weise kann eine große Menge unerwünschter Werbung vermieden werden.
Das Framework hat eine Funktion zum Erzeugen einer CAPTCHA-Grafik im PNG-Format (Mime-Type "image/png"), welche einen zufällig erzeugten Code aus Zahlen und Buchstaben enthält. Ein Parameter gibt an, welche Positionsnummer dieser Code in der aktuellen Code-Tabelle hat. Die Codetabelle enthält 10 Einträge und verfällt in einem Zeitraum von 10 Minuten bis etwa 3 Stunden nach dem Aufruf der Funktion automatisch. Wenn die Tabelle abgelaufen ist, wird automatisch eine neue Tabelle erstellt.
Das Yana Framework hat eine solche Funktion bereits eingebaut. Sie müssen sich also nicht selbst darum kümmern, sondern es lediglich benutzen.
Das CAPTCHA besteht aus zwei Teilen: einer Grafik mit einem Input-Feld, welche im Template eingebunden werden müssen und einer Abfrage, welche im Quellcode des Plugins eingebunden werden muss und die true beziehungsweise false liefert, wenn die Eingabe korrekt beziehungsweise falsch war.
Dazu folgendes Beispiel:
[%captcha%]
Abbildung: Beispiel für die Darstellung im Browser
<?php global $YANA; /** * zum Prüfen der Eingabe: * * Die Variable $formular_daten kann je nach Bedarf auf * $_POST, $_GET, oder $ARGS gesetzt werden. */ $bool = $YANA->handle("security_check_image", $formular_daten);
if ($bool) { print "Eingabe korrekt."; } else { print "Eingabe ist falsch."; } ?>
Die Unterstützung für CAPTCHAs wurde in Version 2.8.0 eingeführt. Das obige Beispiel gilt für das Yana Framework ab Version 2.9.3. In dieser Version wurde die Handhabung des CAPTCHA deutlich vereinfacht.
Für die älteren Versionen 2.8.0 bis 2.9.2 verwenden Sie bitte das folgende Beispiel:
<input type="hidden" name="security_image_index" value="[%$SECURITY_IMAGE_INDEX%]">
<img src=[%"action=security_get_image&security_image_index=$SECURITY_IMAGE_INDEX"|url%]>
<input type="text" name="security_image">
Quellcode des Plugins:
<?php global $YANA; /* zum Erzeugen des Formulars: */ /* Die Variable SECURITY_IMAGE_INDEX muss für das Formular gesetzt werden. Sie kann einen beliebigen Integerwert zwischen 1 und 9 haben. */ $YANA->setVar("SECURITY_IMAGE_INDEX", rand(1,9)); /** * zum Prüfen der Eingabe: * * Die Variable $formular_daten kann je nach Bedarf auf * $_POST, $_GET, oder $ARGS gesetzt werden. */ $bool = $YANA->handle("security_check_image", $formular_daten);
if ($bool) { print "Eingabe korrekt."; } else { print "Eingabe ist falsch."; } ?>
Für noch ältere Versionen (älter als Version 2.8.0) ist ein Einbau von Hand erforderlich.
Die Schnittstelle eines Plugins wird als Datei mit der Endung "*.config" gespeichert. Sie finden diese Dateien im Verzeichnis "plugins/".
/* in der Schnittstellenbeschreibung plugins/foo.config */ <INTERFACE> <name der aktion> <TYPE>primary|default|write|read|security|config</TYPE> /* Type: - "primary" für Kernprozesse eines Hauptprogramms - "security" für sicherheitsrelevante Funktionen, wie das Prüfen von Passwörtern - "config" für Funktionen zum Editieren von Konfigurationsdateien - "write" für Schreibzugriffe auf dem Dateisystem oder einer Datenbank - "read" für Lesezugriffe auf dem Dateisystem oder einer Datenbank - "default" ist gedacht für Entwickler, die sich unschlüssig sind, wo die Aktion einzuordnen ist */ <MODE>0|1</MODE> /* Mode: - 0 (default) normaler Betriebsmodus - 1 Aktion im Default-Konfiguration ("abgesicherter Modus") starten (für sicherheitskritische Aufgaben) */ <TEMPLATE>Id des Templates (z.Bsp. INDEX)</TEMPLATE> <INSERT>Id des Templates (z.Bsp. MY_TEMPLATE)</INSERT> /* Templates: Namen von Templates für die Ausgabe - das unter "INSERT" angegebene Datei wird in die "TEMPLATE"-Datei eingebettet - "TEMPLATE" bildet also einen statischen "Rahmen" um den Inhalt, Defaultwert ist "INDEX" - Der Name des Templates entspricht dem Namen, der in der Skindatei festgelegt wurde. Zum Vergleich öffnen Sie bspw. die Datei skins/default/default.config . - Das spezielle Template "NULL" unterbindet dass eine Ausgabe erzeugt wird (sehr praktisch wenn die Ausgabe keine HTML-Datei sondern bspw. eine PNG-Grafik werden soll) - Das spezielle Template "MESSAGE" erzeugt eine Textmeldung. */ <PERMISSION>1</PERMISSION> /* Permission: Gibt an, welche Zugriffsrechte für einen Nutzer mindestens erforderlich sind, um die Aktion aufrufen zu können. Der Wert liegt zwischen 0 und 100, wobei der Wert 0 = "keine Beschränkung" bedeutet. Sie können eine Funktion temporär deaktivieren, indem Sie die Permission auf -1 setzen. In diesem Fall kann niemand die Aktion aufrufen. */ <ONSUCCESS> <TEXT>Name der Textmeldung</TEXT> <GOTO>Name der Aktion</GOTO> </ONSUCCESS> <ONERROR> <TEXT>Name der Textmeldung</TEXT> <GOTO>Name der Aktion</GOTO> </ONERROR> /* OnSuccess / OnError: Sie können eine Aktion angeben, auf welche automatisch weitergeleitet werden soll, wenn die Aktion erfolgreich war beziehungsweise, wenn ein Fehler aufgetreten ist. Zusätzlich können Sie eine Textmeldung angeben, welche angezeigt werden soll. Eine Liste der Textmeldungen finden Sie in der Datei "languages/de/message.config". */ </name der aktion> /* ein Beispiel */ <foo> <TYPE>write</TYPE> <MODE>0</MODE> <TEMPLATE>MESSAGE</TEMPLATE> <PERMISSION>75</PERMISSION> <ONSUCCESS> <GOTO>foo_read</GOTO> </ONSUCCESS> <ONERROR> <GOTO>foo_edit</GOTO> </ONERROR> <foo> </INTERFACE> in der Plugin-Klasse plugins/foo/plugin.php: <?php class plugin_foo extends plugin { /* ... */ function foo($ARGS) { /* Quelltext der Aktion "foo" */ if ($test) { return true; /* true = SUCCESS -> gehe zu Aktion "foo_read" */ } else { return false; /* false = ERROR -> gehe zu Aktion "foo_edit" */ } } function foo_edit($ARGS) { /* Quelltext der Aktion "foo_edit" */ } function foo_read($ARGS) { /* Quelltext der Aktion "foo_read" */ } } ?>
Zuerst sollten Sie mit Hilfe des SDK ein Grundgerüst für Ihr neues Plugin generieren lassen. Dies macht das Anpassen des Quellcodes deutlich einfacher.
Für das Erstellen einer neuen Aktion sind zwei Dinge erforderlich. Einerseits das Schreiben des Quellcodes und andererseits die Registrierung dieser neuen Aktion im Framework selbst durch Publizieren der Schnittstelle. Dadurch wird es überhaupt erst möglich, die Aktion aufzufinden und zu benutzen.
Im Folgenden ein Beispiel: Alle öffentlichen Funktionen der Klasse stellen eine Funktion bereit, die ebenso heißt, wie die Funktion selbst. Also: um eine Aktion "foo" zu erzeugen, erstellen Sie eine Funktion "foo()". Diese rufen Sie in der URL auf über: "index.php?action=foo".
Achten Sie im Folgenden Beispiel auf die "Hot-Spots". Diese markieren Stellen im Skelett der Anwendung, welche mit eigenem Code befüllt werden können.
<?php class plugin_beispiel extends plugin { function plugin_beispiel($plugin_name) { settype($plugin_name,"string"); global $YANA; $this->plugin_name = $plugin_name; } /** * Default event handler * * @param string $event name of the called event in lower-case * @param array $ARGS array of params passed to the function * @return boolean */ function _default($event, $ARGS) { settype($event, "string"); settype($ARGS, "array"); # HOT-SPOT << hier können Sie Aktionen definieren # zum Beispiel mit einer Switch-Anweisung: switch ($event) { case 'my_action1': # HOT-SPOT << Code für Aktion 'my_action1' break; case 'my_action2': # HOT-SPOT << Code für Aktion 'my_action2' break; } return true; } /** * Type: read * Permission: 0 * Templates: index entries * * @param array $ARGS array of params passed to the function * @return boolean */ function guestbook_read_entries ($ARGS) { # HOT-SPOT << Code für Aktion 'guestbook_read_entries' } /* { ... } */ /** * Type: write * Permission: 100 * Templates: MESSAGE * * @param array $ARGS array of params passed to the function * @return boolean */ function guestbook_write_write ($ARGS) { # HOT-SPOT << Code für Aktion 'guestbook_write_write' $YANA->message("OK", "200"); } function my_action ($ARGS) { # HOT-SPOT << Code für Aktion 'my_action' } } ?>
Die "Hot-Spots", an welchen der Entwickler eigenen Quellcode schreiben oder ergänzen kann, sind in diesem kurzen Beispiel entsprechend hervorgehoben. Die Funktion "my_action" soll demonstrieren, wie man nachträglich eigene Aktionen zur Schnittstelle der Klasse und damit zum Plugin hinzufügen kann. Beachten Sie die Funktion "_default". Diese wird von der Basisklasse "plugin" geerbt und fungiert als "Default event handler", welcher alle Ereignisse abfängt, die an das Plugin gesendet werden, aber über die Schnittstelle der Klasse nicht implementiert sind. Außerdem fängt diese Funktion Exoten ab, wie beispielsweise Ereignisse welche ungünstigerweise ebenso benannt sind wie der Konstruktor der Klasse selbst, oder solche, welche von der Basisklasse "plugin" geerbt wurden und somit nicht zur vom Nutzer definierten Schnittstelle der Klasse gehören können. Dies betrifft aus Sicherheitsgründen auch solche, welche in der abgeleiteten Klasse reimplementiert werden. Der Grund hierfür ist, dass diese Methoden öffentlich sind. Sie sind somit Teil einer gemeinsamen Schnittstelle aller von der Klasse "plugin" abgeleiteten Klassen. Ihre Funktionalität wird folglich gewissermaßen durch die Implementierung der Basisklasse vorgegeben und zugesichert. Sie sollte auch in den abgeleiteten Klassen erhalten bleiben.
Um eine Funktion zu erzeugen, die nicht in der öffentlichen Schnittstelle auftauchen soll, kennzeichnen sie diese Funktion als "private".
Bitte beachten: damit die neuen Funktionen verfügbar werden, müssen Sie den Plugin-Cache erneuern. Dazu loggen Sie sich als Administrator ein und klicken im Administrationsmenü auf "Liste neu laden".
Die "Setup-Menüs" finden Sie im Administrationsmenü in der Spalte "Optionen" (links), wie in folgender Abbildung.
Um den Menüeintrag und das dazu passende Setup zu erzeugen, genügt ein Eintrag in der Konfigurationsdatei des Plugins und ein HTML-Template. Es ist dazu nicht erforderlich PHP-Code zu schreiben. Betrachte Sie folgendes Beispiel der Konfigurationsdatei eines Plugins:
Datei "plugins/beispiel.config" <INFO> /* Zuerst die obligatorischen Angaben - diese haben mit dem * Setup-Menü noch nichts zu tun. */ <ID>foo</ID> <NAME>Foo plugin</NAME> <AUTHOR>Thomas Meyer</AUTHOR> <DESCRIPTION>mein Beispiel-Plugin</DESCRIPTION> <LOGO>%PLUGINDIR%foo/preview.jpg</LOGO> <IMAGE>%PLUGINDIR%foo/icon.png</IMAGE> <TYPE>primary</TYPE> /* Hier folgen die Einträge für das Setup-Menü */ <SETUP> /* Der folgende Code erzeugt einen Eintrag mit * der Beschriftung "Foo Options" und dem Icon * "plugins/foo/setup1.gif". Bei Klick auf die * Schaltfläche "Setup" wird die Aktion * "foo_setup_1" ausgelöst. */ <0> <ACTION>foo_setup_1</ACTION> <TITLE>Foo Options</TITLE> </0> /* Ein zweites Beispiel: */ <1> <ACTION>foo_setup_2</ACTION> <TITLE>Bar Options</TITLE> </1> </SETUP> </INFO> <INTERFACE> /* Den Aktionen "foo_setup_1" und "foo_setup_2" * wird nun noch ein Template zugeordnet */ <foo_setup_1> /* TYPE=config definiert, dass es ein Setup-Menü ist */ <TYPE>config</TYPE> /* PERMISSION=100 beschränkt den Zugriff auf Nutzer * mit der Sicherheitsstufe 100 - das sind Administratoren. */ <PERMISSION>100</PERMISSION> /* foo_template_1 ist der Name des Templates */ <INSERT>foo_template_1</INSERT> </foo_setup_1> <foo_setup_2> <TYPE>config</TYPE> <PERMISSION>75</PERMISSION> <INSERT>foo_template_2</INSERT> </foo_setup_2> /* ... hier folgen noch eventuell andere Aktionen ... */ </INTERFACE>
Nun benötigen Sie noch eine HTML-Seite mit einem Formular, wie in folgendem Beispiel:
Datei "skins/default/beispiel.html"
<!-- Den Kopf der Datei sollten Sie einfach übernehmen. Hier gibt es nichts
zu editieren. Copy'n'Paste reicht völlig aus. -->
<!-- BEGINN: Kopf -->
<form method="POST" enctype="multipart/form-data" action="[%$PHP_SELF%]">
[%if !$ID%][%if $PERMISSION==100%]
<input type="hidden" name="action" value="set_config_profile">
[%/if%][%else%]
<input type="hidden" name="action" value="set_config_profile">
[%/if%]
<input type="hidden" name="[%$SESSION_NAME%]" value="[%$SESSION_ID%]">
<input type="hidden" name="id" value="[%$ID%]">
<!-- ENDE: Kopf -->
<!-- Nun folgt der variable Teil, den Sie selbst ausfüllen können -->
<!-- eine Überschrift macht sich gut: -->
<h1>Setup</h1>
<!-- eine Liste mit Optionen -->
<label>Option 1
<!-- $PROFILE.OPT1 ist der gespeicherte Wert für dieses Feld -
sofern bereits einmal ein Wert gespeichert wurde.
Der Modifier |entities sorgt dafür, Tag-Klammern und
Anführungszeichen in HTML-Entitäten umgewandelt werden, damit
keine HTML-Syntaxfehler entstehen können.
-->
<input type="text" name="opt1" value="[%$PROFILE.OPT1|entities]">
</label><br>
<label>Option 2
<input type="text" name="path.opt2" value="[%$PROFILE.PATH.OPT2|entities]">
</label><br>
<label>Option 3
<input type="text" name="opt3" value="[%$PROFILE.OPT3|entities]">
</label><br>
<!-- die Schaltfläche zu Abschicken nicht vergessen -->
<input type="submit" value="[%$LANGUAGE.SPEICHERN%]">
</form>
Diese HTML-Seite bewirkt, dass nach dem Abschicken des Formulars folgendes Array gespeichert wird:
<?php $PROFILE = array( 'opt1' => "foo", 'path' => array( 'opt2' => "bar" ), 'opt3' => "foobar" ); ?>
Sie können in Ihrem Plugin wie folgt auf die gespeicherten Optionen zugreifen:
<?php global $YANA; $opt1 = $YANA->getVar('PROFILE.OPT1'); $path_opt2 = $YANA->getVar('PROFILE.PATH.OPT2'); $opt3 = $YANA->getVar('PROFILE.OPT3'); ?>
Damit das Formular "beispiel.html" bei Klick auf die Schaltfläche "Setup" auch angezeigt wird, muss es mit der Aktion "foo_setup_1" verknüpft werden. Dies geht wie folgt:
Datei "skins/default/beispiel.config"
<!-- Hier wird zunächst das Template unter dem Namen "foo_template_1" definiert ... -->
<foo_template_1>
<FILE>beispiel.html</FILE>
</foo_template_1>
Datei "plugins/beispiel.config"
...
<INTERFACE>
<foo_setup_1>
<TYPE>config</TYPE>
<PERMISSION>100</PERMISSION>
<!-- ... und hier wird das Template "foo_template_1" der Aktion "foo_setup_1" zugeordnet. -->
<INSERT>foo_template_1</INSERT>
</foo_setup_1>
...
</INTERFACE>
<?php $image = new Image('dateiname'); // zum Beispiel: $image = new Image('ordner/datei.png'); ?>
<?php $content = file_get_contents('ordner/datei.png'); $image = new Image($content, 'png'); ?>
<?php $image = new Image(); $width = 640; $height = 480; $image->resize($width, $height); ?>
<?php $image = new Image('ordner/datei.png'); $width = 50; // wenn die Höhe ($height) nicht angegeben wird, // dann wird die Grafik proportional verkleinert $image->resize($width); $image->outputToFile('ordner/thumbnail.png'); ?>
<form method="POST" action="%PHP_SELF%" enctype="multipart/form-data">
(...)
Upload image: <input type="file" name="my_image" />
(...)
</form>
<?php // get data from form field 'my_image' $id = 'my_image'; // output to directory 'foo/bar/' using filename 'image' // (extension will be determined automatically) $file = 'foo/bar/image'; // output as png image $type = 'png'; // limit upload to 150 kbyte $size = 150000; // resize to 150px x 200px $width = 150; $height = 200; // leave aspect-ratio untouched $ratio = true; // set background color to gray $color = array(80, 80, 80); // call method $result = Image::uploadFile($id, $file, $type, $size, $width, $height, $ratio, $color); // check for errors if (is_string($result)) { print "The image was successfully uploaded to '$result'"; // error handling } else { switch ($result) { case UPLOAD_ERR_SIZE: case UPLOAD_ERR_INI_SIZE: case UPLOAD_ERR_FORM_SIZE: die('File too big!'); break; case UPLOAD_ERR_NO_FILE: die('No file has been uploaded!'); break; case UPLOAD_ERR_INVALID_TARGET: die("Unable to write to file: '$file'"); break; case UPLOAD_ERR_FILE_TYPE: die('The file is not a recognized image!'); break; default: die('Some unexpected error occured!'); break; } } ?>
<?php // erzeuge leeres Bild $image = new Image(); $width = 180; $height = 120; $image->resize($width, $height); // setze die Linienbreite auf 3px (optional) $image->setLineWidth(3); // die Leinwand mit einer Hintergrundfarbe füllen $x = 0; $y = 0; $image->fill($image->white, $x, $y); // Zeichne eine Linie $x1 = 10; $y1 = 10; $x2 = 100; $y2 = 30; $image->drawLine($x1, $y1, $x2, $y2, $image->black); // Zeichne einen Kreis $x = 30; $y = 50; $width = 50; $image->drawEllipse($x, $y, $width); // Zeichne ein Rechteck $x = 10; $y = 60; $width = 100; $height = 50; $rahmenFarbe = $image->black; $fuellFarbe = $image->navy; $image->drawRectangle($y, $y, $width, $height, $rahmenFarbe, $fuellFarbe); // Zeichne ein Dreieck (oder anderes Polygon) $points = array( 0 => array( 20, 0 ), 1 => array( 40, 20 ), 2 => array( 0, 20 ) ); $x = 50; $y = 80; $rahmenFarbe = $image->black; $fuellFarbe = $image->yellow; $image->drawPolygon($points, $x, $y, $rahmenFarbe , $fuellFarbe); // Schreibe einen Text $text = 'Hallo Welt!'; $x = 70; $y = 40; $textFarbe= $image->black; $image->drawString($text, $x, $y, $textFarbe); // Verwenden von Pinseln // neuen Pinsel erzeugen $brush = new Brush('small star'); // setze Größe des Pinsels auf 10px $brush->setSize(10); // setze die Farbe des Pinsels auf rot $brush->setColor(255, 0, 0); // den Pinsel auswählen $image->setBrush($brush); // zeichne einen Punkt und benutze dabei den Pinsel $x = 150; $y = 100; $image->drawPoint($x, $y, IMG_COLOR_BRUSHED); // Ausgabe der Grafik an den Browser $image->outputToScreen('png'); exit; ?>
Abbildung: Ausgabe des Skripts
Wenn Sie mit Grafiken arbeiten, dann brauchen Sie Farben, um Linien, Texte oder Flächen zu zeichnen.
Es gibt 17 vordefinierte Farben. Diese lauten:
Weitere Farben können Sie erhalten durch Aufruf von: $color = $image->getColor($rot, $gruen, $blau); Dabei dürfen $rot, $gruen und $blau ganze Zahlen zwischen 0 und 255 sein.
Es ist wichtig, dass Sie verstehen, dass eine Farbe kein Objekt ist, dass für sich selbst existiert, sondern eine spezifische Eigenschaft einer Grafik. Das kommt daher, dass jede Grafik eine eigene Farbpalette besitzt und jede Farbe ein Teil (mathematisch gesprochen ein "Element") dieser Palette ist.
Die Palette des Bildes ist eine indexierte Menge aller in der Grafik enthaltenen Farben. Eine Farbe wird dabei dargestellt als ganze Zahl. Genauer: es handelt sich um Indexnummer der Farbe innerhalb der Farbpalette des Bildes. Das heißt, die Zahl 1 bezeichnet beispielsweise die Farbe, welche in der Farbpalette der Grafik die Positionsnummer 1 hat. Diese Farbe könnte am Bildschirm zum Beispiel "rot" aussehen. Beachten Sie jedoch, dass diese Zuordnung abhängig ist von der Farbpalette und somit vom gerade angezeigten Bild.
Hier eine Liste interessanter Methoden der Klasse Image und was diese bewirken:
<?php $image = new Image('foo.png'); /* Helligkeit einstellen * * Zahl zwischen -1.0 und +1.0 (-100% und +100%) */ $ammount = 0.5; /* 0.5 = +50% */ $image->brightness($ammount); ?>
Abbildung: Ausgabe des Skripts
<?php /* Kontrast einstellen * * Zahl zwischen -1.0 und +1.0 (-100% und +100%) */ $ammount = 0.5; /* 0.5 = +50% */ $image->contrast($ammount); ?>
Abbildung: Ausgabe des Skripts
<?php /* Unscharfmaske anwenden * * Zahl zwischen 0.0 und +1.0 (0% und +100%) */ $ammount = 0.8; /* 0.8 = 80% */ $image->blur($ammount); ?>
Abbildung: Ausgabe des Skripts
<?php /* Bildschärfe erhöhen * * Zahl zwischen 0.0 und +1.0 (0% und +100%) */ $ammount = 0.8; /* 0.8 = 80% */ $image->sharpen($ammount); ?>
Abbildung: Ausgabe des Skripts
<?php /* in Graustufen umwandeln */ $image->toGrayscale(); ?>
Abbildung: Ausgabe des Skripts
<?php /* Einfärben (Kolorieren) * * $rot, $gruen, $blau = Zahlen zwischen -255 und 255 * * Der Farbwert wird zur Farbe der Grafik addiert */ $rot = -80; $gruen = -40; $blau = 120; $image->colorize($rot, $gruen, $blau); ?>
Abbildung: Ausgabe des Skripts
<?php /* Multiplizieren * * $rot, $gruen, $blau = Zahlen zwischen 0 und 255 * * Der Farbwert wird mit der Farbe der Grafik multipliziert */ $rot = 100; $gruen = 255; $blau = 50; /* dieses Beispiel reduziert den Rot- und Blaukanal */ $image->multiply($rot, $gruen, $blau); ?>
Abbildung: Ausgabe des Skripts
<?php /* Monochromatischer Filter * * $rot, $gruen, $blau = Zahlen zwischen 0 und 255 * * Färbt die Grafik mit der angegeben Farbe ein. */ $rot = 130; $gruen = 180; $blau = 200; $image->monochromatic($rot, $gruen, $blau); ?>
Abbildung: Ausgabe des Skripts
<?php /* Farbwerte umkehren (Negativeffekt) */ $image->negate(); ?>
Abbildung: Ausgabe des Skripts
Details und Beispiele zu weiteren Funktionen finden Sie in der API-Dokumentation.
Das Yana Framework verfügt über vordefiniertes CSS zum Erzeugen von Texten oder Seiten mit 2, 3 oder mehr vertikalen Spalten. Dazu ist keine Programmierung Ihrerseits erforderlich. Der erforderliche CSS-Code wird im "Default"-Skin automatisch geladen.
Im Folgenden folgen einige Beispiele zur Demonstration
Quellcode des Templates:
<div class="multicol2">
<div class="col_left">
<h2>Spalte 1</h2>
Nulla ultrices lacinia mi. Nulla dapibus, risus vitae imperdiet
commodo, ipsum ligula lacinia orci, non venenatis metus ligula
sit amet turpis. Nunc accumsan tempor nulla. Vivamus eleifend,
lectus eu feugiat consequat, mi lacus vestibulum velit, eu
egestas purus nunc ac est. Mauris massa lorem, lacinia non,
condimentum vel, cursus ac, lectus. Nulla tempor molestie quam.
Aenean dapibus nisl nonummy quam. Mauris pellentesque ornare
ante. Integer a urna ultricies neque bibendum dignissim.
Suspendisse interdum nisl. In rhoncus. Vivamus risus mi, semper
id, lobortis et, auctor in, nulla. Sed placerat posuere tortor.
In vitae augue.
</div>
<div class="col_right">
<h2>Spalte 2</h2>
Aliquam auctor viverra ligula. Ut nisi felis, condimentum at,
aliquam eget, tempus id, nisi. Maecenas a libero. Nulla metus
mi, malesuada sit amet, sagittis bibendum, scelerisque a, purus.
Nunc ipsum. Sed vel augue pellentesque ligula pharetra pulvinar.
Class aptent taciti sociosqu ad litora torquent per conubia
nostra, per inceptos hymenaeos. Nam orci. Donec neque pede,
iaculis in, pellentesque ac, commodo eget, libero. Sed vel
magna.
</div>
<div class="col_foot"> </div>
</div>
Quellcode des Templates:
<div class="multicol3">
<div class="col_left">
<h2>Spalte 1</h2>
Nulla ultrices lacinia mi. Nulla dapibus, risus vitae imperdiet
commodo, ipsum ligula lacinia orci, non venenatis metus ligula
sit amet turpis. Nunc accumsan tempor nulla. Vivamus eleifend,
lectus eu feugiat consequat, mi lacus vestibulum velit, eu
egestas purus nunc ac est. Mauris massa lorem, lacinia non,
condimentum vel, cursus ac, lectus. Nulla tempor molestie quam.
Aenean dapibus nisl nonummy quam. Mauris pellentesque ornare
ante. Integer a urna ultricies neque bibendum dignissim.
Suspendisse interdum nisl. In rhoncus. Vivamus risus mi, semper
id, lobortis et, auctor in, nulla. Sed placerat posuere tortor.
In vitae augue.
</div>
<div class="col_center">
<h2>Spalte 2</h2>
Aliquam auctor viverra ligula. Ut nisi felis, condimentum at,
aliquam eget, tempus id, nisi. Maecenas a libero. Nulla metus
mi, malesuada sit amet, sagittis bibendum, scelerisque a, purus.
Nunc ipsum. Sed vel augue pellentesque ligula pharetra pulvinar.
Class aptent taciti sociosqu ad litora torquent per conubia
nostra, per inceptos hymenaeos. Nam orci. Donec neque pede,
iaculis in, pellentesque ac, commodo eget, libero. Sed vel
magna.
</div>
<div class="col_right">
<h2>Spalte 3</h2>
Morbi eget dolor. Etiam ut velit sollicitudin massa laoreet
lobortis. Ut vel sem id enim ornare ultrices. Morbi justo
tortor, blandit sed, euismod at, eleifend nec, tortor. Lorem
ipsum dolor sit amet, consectetuer adipiscing elit. Etiam eget
enim. Maecenas vel nisl dapibus metus venenatis volutpat.
Integer ipsum ante, porta eu, porta vel, euismod in, magna.
Fusce dolor quam, lacinia eget, rutrum at, lacinia pulvinar,
risus. Nulla imperdiet, lorem facilisis lacinia suscipit, diam
mi aliquet dui, at fringilla lectus mauris sit amet ipsum.
Morbi eget sem quis est congue pulvinar. Vivamus fermentum
dolor nec nisi convallis posuere. Aliquam eu diam. Ut suscipit,
nisi quis vehicula ullamcorper, lectus lorem fermentum tellus,
ut egestas arcu sapien aliquam massa.
</div>
<div class="col_foot"> </div>
</div>
Es ist möglich mehrspaltige Layouts ineinander zu schachteln. Das folgende Beispiel demonstriert, wie zwei 2-spaltige Layouts ineinander verschachtelt werden, um ein 4-spaltiges Layout zu erzeugen.
Quellcode des Templates:
<div class="multicol2">
<div class="col_left">
<div class="multicol2">
<div class="col_left">
<h2>Spalte 1</h2>
Vestibulum tempor commodo mi. Integer sed nisi. Donec
nulla elit, commodo porttitor, semper eget, sagittis
viverra, urna. Duis pretium dui facilisis turpis.
Mauris vel arcu. Donec ut lorem vel lorem aliquet
commodo. Donec sollicitudin mattis lacus. Ut non magna
sit amet tortor viverra sagittis. Ut venenatis.
Vestibulum sodales sapien scelerisque erat. Integer
accumsan orci et tortor vulputate mollis. Curabitur
lacinia quam id libero. Nulla eu lorem eget mi mattis
tempus. Suspendisse consectetuer. Vivamus at risus.
Aenean malesuada.
</div>
<div class="col_right">
<h2>Spalte 2</h2>
Morbi id nisi. Proin fringilla eleifend mi. Nunc eget
elit. Nam ligula nibh, euismod blandit, nonummy eu,
porta non, magna. Ut id nisi id metus consectetuer
euismod. Vestibulum ante ipsum primis in faucibus orci
luctus et ultrices posuere cubilia Curae; Mauris
blandit ultrices eros. Fusce in nisl sit amet enim
consequat tristique. Sed facilisis eros convallis magna.
Pellentesque justo. Praesent nec libero at velit
malesuada nonummy. Mauris vitae lectus eget elit
euismod bibendum. Nulla nec ligula. Curabitur metus.
Integer lectus nulla, iaculis molestie, venenatis non,
suscipit commodo, est. Sed pulvinar, justo eu pulvinar
convallis, mi tellus pellentesque elit, eu aliquet
sapien ligula non mauris.
</div>
</div>
</div>
<div class="col_right">
<div class="multicol2">
<div class="col_left">
<h2>Spalte 3</h2>
Praesent eu risus. Fusce feugiat. Maecenas eget lacus
quis nisi blandit porttitor. Pellentesque sed turpis.
Nulla facilisi. Aenean convallis dolor eget elit. Donec
elementum, pede nec euismod varius, ante diam elementum
lectus, vitae iaculis orci libero quis tortor.
Vestibulum justo est, laoreet eu, consequat sed,
molestie at, mi. Fusce luctus, odio eu imperdiet
viverra, nunc arcu gravida ante, iaculis lacinia tortor
arcu ac felis. Quisque sagittis aliquam nisi. Aliquam
nonummy. Nulla mattis orci vel nunc. Nunc in odio.
Proin mi risus, lobortis ac, mollis vitae, lacinia
vehicula, nulla. Nunc nibh. Morbi laoreet pellentesque
justo. Praesent ultrices.
</div>
<div class="col_right">
<h2>Spalte 4</h2>
Nullam eget lectus. Aenean non augue auctor erat luctus
fermentum. Quisque aliquam eros vel ligula. Mauris pede
velit, mollis eget, adipiscing non, placerat nec, erat.
Vestibulum vel sem non orci porttitor congue. Cras
pretium eros eget dui. Donec gravida. Sed mattis
tincidunt enim. Donec aliquam, quam eu rhoncus gravida,
nibh nunc egestas nulla, lobortis interdum nisi dui id
nisi. Praesent tristique velit sit amet ante. Nam
malesuada, nisi in laoreet venenatis, dolor pede
vehicula nunc, tempus accumsan ante purus eget sapien.
Praesent aliquam, lorem sit amet volutpat faucibus,
ligula lorem auctor diam, vitae vulputate pede ligula
et leo.
</div>
</div>
</div>
<div class="col_foot"> </div>
</div>
Das Yana Framework bietet Ihnen zum Erstellen aufklappbarer Baummenüs mehrere Lösungen an. Aufwendige Programmierung ist dazu nicht erforderlich.
Folgende Möglichkeiten stehen Ihnen zur Verfügung:
Für beide Varianten haben Sie die Wahl zwischen derzeit zwei verschiedenen Layouts. Dieses Kapitel enthält folglich drei Abschnitte. Zuerst wird Ihnen jeweils für 1. und 2. Layout gezeigt, wie Sie den HTML-Quellcode der Menüs von Hand schreiben können. Danach wird Ihnen demonstriert, wie Sie die Template-Funktion "printUnorderedList" verwenden können, um sich diese Menüs automatisch generieren zu lassen.
In diesem Abschnitt wird beschrieben, wie Sie ein aufklappbares Menü direkt im HTML erstellen können. Um die Funktionalität und die Darstellung kümmert sich das Yana Framework automatisch.
Dies ist der 1. Layoutvorschlag. Er verwendet JavaScript und CSS zur Darstellung des Menüs. Im Anschluss wird ein 2. Layoutvorschlag vorgestellt, welcher alternativ verwendet werden kann und ausschließlich CSS verwendet.
Das Layout wird in der Datei "skins/default/styles/menu.css" festgelegt und kann über folgende CSS-Klassen gesteuert werden:
Die Darstellung des Menüs entspricht den gängigen Empfehlungen und ist suchmaschinenfreundlich.
Gehen Sie wie folgt vor:
Abbildung: Darstellung des Menüs
<ul class="menu root">
<li class="entry"><a href="ziel.html">Link</a></li>
<li class="menu">
<div onclick="yanaMenu(this)">Menü 1</div>
<ul class="menu">
<li class="entry"><a href="1.html">Eintrag 1</a></li>
</ul>
</li>
<li class="menu">
<div onclick="yanaMenu(this)">Menü 2</div>
<ul class="menu">
<li class="entry"><a href="2.html">Eintrag 2</a></li>
<li class="menu">
<div onclick="yanaMenu(this)">Submenü 2.1</div>
<ul class="menu">
<li class="entry">
<a href="2_1.html">Eintrag 2.1</a>
</li>
<li class="entry">
<a href="2_2.html">Eintrag 2.2</a>
</li>
<li class="entry">
<a href="2_3.html">Eintrag 2.3</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="menu">
<div onclick="yanaMenu(this)">geschlossen</div>
<ul class="menu" style="display: none;">
<li class="entry"><a href="2.html">(unsichtbar)</a></li>
</ul>
</li>
</ul>
Das Attribut "onclick" enthält hier den Aufruf zum Öffnen und Schließen des Menüs. "Style"-Attribute legen abweichende Eigenschaften fest, wobei "display: none" das Menü ausblendet. Menüs sind von einem Element der CSS-Klasse "menu" umschlossen. Menüeinträge sind umschlossen von einem Element der CSS-Klasse "entry". Die Überschrift eines Menüs wird mit "div"-Tags umschlossen, welche auch das Attribut "onclick" erhalten. Durch Anklicken der Überschrift kann das Menü geschlossen oder geöffnet werden.
Tipp: es ist in der Regel einfacher, zunächst eine einfache Liste mit den Tags "ul", "li" zu erstellen und die CSS-Klassen und JavaScript-Codes nachträglich zu ergänzen, anstatt das Menü Zeile für Zeile zu beschreiben. Dadurch bleibt der Code während der Bearbeitung übersichtlicher.
Es gilt folgende Voreinstellung: alle Menüs sind zunächst geöffnet, wenn Sie nicht explizit als geschlossen gekennzeichnet sind. Es können mehrere Menüs gleichzeitig geöffnet sein.
Falls Sie wünschen, dass stets nur 1 Menü gleichzeitig geöffnet ist, fügen Sie folgenden Quellcode hinzu:
<script
type="text/javascript">
yana_menu_auto_close = true;
</script>
Falls Sie wünschen, dass zu Beginn alle Menüs geschlossen sind, verwenden Sie folgenden Quellcode:
<script
type="text/javascript">
yanaCloseAll();
</script>
Beide Varianten können kombiniert werden.
<script
type="text/javascript">
yana_menu_auto_close = true;
yanaCloseAll();
</script>
Abbildung: Darstellung des Menüs
<ul class="hmenu">
<li class="entry">
<a href="ziel.html">Link 1</a>
</li>
<li onmouseover="yanaHMenu(this,true)" onmouseout=
"yanaHMenu(this,false)" class="hmenu">
<div class="menu_head">
Menü 1
</div>
<ul class="hmenu">
<li class="entry">
<a href="1.html">Eintrag 1</a>
</li>
</ul>
</li>
<li onmouseover="yanaHMenu(this,true)" onmouseout=
"yanaHMenu(this,false)" class="hmenu">
<div class="menu_head">
Menü 2
</div>
<ul class="hmenu">
<li class="entry">
<a href="2.html">Eintrag 2</a>
</li>
<li onmouseover="yanaHMenu(this,true)" onmouseout=
"yanaHMenu(this,false)" class="hmenu">
<div class="menu_head">
Submenü 2.1
</div>
<ul class="hmenu">
<li class="entry">
<a href="2_1.html">Eintrag 2.1</a>
</li>
<li class="entry">
<a href="2_2.html">Eintrag 2.2</a>
</li>
<li class="entry">
<a href="2_3.html">Eintrag 2.3</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="entry">
<a href="3.html">Link 2</a>
</li>
</ul>
Das Menü funktioniert vollständig mit CSS und ohne JavaScript. Allerdings wird hier zusätzlich JavaScript verwendet, damit ältere Browser und Browser mit unvollständiger CSS-Unterstützung, wie zum Beispiel der Internet Explorer 6.0, die Seite trotzdem wie erwartet darstellen.
Jedes Menü ist zunächst geschlossen und wird temporär geöffnet, wenn der Nutzer mit der Maus darauf zeigt.
Wenig Unterschiede zum vertikalen Menü gibt es bei den CSS-Klassen. Achten Sie lediglich darauf, dass hier statt der Klasse "menu" die Klasse "hmenu" verwendet wird.
Dies ist der 2. Layoutvorschlag. Die Menüs öffnen sich automatisch wenn Sie mit der Maus berührt werden. In Firefox, Opera und Co. funktioniert das Ein- und Ausklappen des Menüs vollständig über CSS (ohne JavaScript). Lediglich im Internet Explorer einschließlich Version 7 muss JavaScript aktiviert sein, da dieser Browser die erforderlichen CSS 2.1 Pseudoklassen noch nicht vollständig unterstützt.
Das Layout wird in der Datei "skins/default/styles/gui_array.css" festgelegt und kann über folgende CSS-Klassen gesteuert werden:
Gehen Sie wie folgt vor:
Abbildung: Darstellung des Menüs
<ul class="gui_array_list">
<li class="gui_array_list">
<a class="gui_array_value" href="ziel.html">Link 1</a>
</li>
<li class="gui_array_head"
onmouseover="this.className='gui_array_head_open'"
onmouseout="this.className='gui_array_head'">
<span class="gui_array_key">Menü 1</span>
<ul class="gui_array_list">
<li class="gui_array_list">
<a class="gui_array_value" href="1.html">Eintrag 1</a>
</li>
</ul>
</li>
<li class="gui_array_head"
onmouseover="this.className='gui_array_head_open'"
onmouseout="this.className='gui_array_head'">
<span class="gui_array_key">Menü 2</span>
<ul class="gui_array_list">
<li class="gui_array_list">
<a class="gui_array_value" href="2.html">Eintrag 2</a>
</li>
<li class="gui_array_head"
onmouseover="this.className='gui_array_head_open'"
onmouseout="this.className='gui_array_head'">
<span class="gui_array_key">Submenü 2.1</span>
<ul class="gui_array_list">
<li class="gui_array_list">
<a class="gui_array_value" href="2_1.html">Eintrag 2.1</a>
</li>
<li class="gui_array_list">
<a class="gui_array_value" href="2_2.html">Eintrag 2.2</a>
</li>
<li class="gui_array_list">
<a class="gui_array_value" href="2_3.html">Eintrag 2.3</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="gui_array_list">
<a class="gui_array_value" href="3.html">Link 2</a>
</li>
</ul>
Das Attribut "onmouseover" dient hier zum Öffnen des Menüs und das Attribut "onmouseout" zum Schließen. Diese Attribute sind jedoch nicht zwingend erforderlich sondern dienen lediglich der Abwärtskompatibilität mit dem Internet Explorer und veralteten Browsern.
Mit der Template-Funktion "printUnorderedList" können Sie automatisch den Inhalt eines mehrdimensionales Arrays als Menü darstellen lassen.
Dazu sind 2 Schritte erforderlich. Zunächst legen Sie im PHP-Quellcode Ihres Plugins ein Array mit den Einträgen Ihres Menüs an. Danach lassen Sie sich im Template über den Aufruf der Funktion "printUnorderedList" das gewünschte Menü aus diesem Array generieren.
Gehen Sie wie folgt vor:
Abbildung: Darstellung des Menüs
<?php global $YANA; $array = array( 'ziel.html' => 'Link 1', 'Menü 1' => array( '1.html' => 'Eintrag 1' ), 'Menü 2' => array( '2.html' => 'Eintrag 2', 'Submenü 2.1' => array( '2_1.html' => 'Eintrag 2.1', '2_2.html' => 'Eintrag 2.2', '2_3.html' => 'Eintrag 2.3' ), ), '3.html' => 'Link 2' ); $YANA->setVar('myMenu', $array); ?>
Wie Sie sehen, enthalten Schlüssel des Arrays die URLs und die Werte enthalten die Beschriftung.
Um das eigentliche Menü generieren zu lassen, gehen Sie wie folgt vor:
Dem Parameter "value" übergeben Sie das Array welches die Einträge des Menüs enthält. Über den Parameter "layout" können Sie zwischen dem 1. und 2. Layout wählen. Den Parameter "keys_as_href" sollten Sie auf den Wert "true" setzen.
Zum Bearbeiten von Aktionen bietet YANA die Funktion $YANA->handle(), welche bei Erfolg bool(true) und sonst bool(false) zurück gibt.
<?php global $YANA; /* Aktion "foo" aufrufen */ $bool = $YANA->handle("foo", $parameter); if ($bool) { print "Die Aktion 'foo' wurde erfolgreich ausgeführt."; } else { print "Der Aufruf von 'foo' hat einen Fehler erzeugt."; } ?>
Dies bewirkt, dass alle Dateien im Verzeichnis "cache/" des Frameworks gelöscht werden.
<?php global $YANA; /* den Template-Cache des Servers leeren */ $YANA->handle("clear_server_cache", array()); ?>
<!-- der folgende Eintrag im Template genügt: -->
<textarea id="eingabefeld" name="text"></textarea>
[%preview%]
Abbildung: Beispiel für die Darstellung im Browser
"Microsummaries" sind "aktive Lesezeichen", dass heißt Links in den Bookmarks, deren Text sich dynamisch aktualisieren kann, wenn sich der Inhalt der Webseite ändert, auf die der Link verweist. Der Firefox-Browser bietet dem Nutzer automatisch die Verwendung von Microsummaries an, wenn dieser einen Bookmark einer Seite erzeugt, welche über dieses Feature verfügt.
Beispiele hierfür wären:
Weitere Varianten sind natürlich denkbar.
Microsummaries werden vom Yana Framework unterstützt. Sie werden mit Hilfe der Utility-Klasse "Microsummary" erzeugt. Im Folgenden einige Beispiele:
<?php /* in einem Plugin ein Mircosummary erzeugen */ Microsummary::set($this->name, 'Text des Links'); /* Bitte beachten: * der erste Parameter ist eine Id, welche den Eintrag * eindeutig identifiziert. * Hier wird $this->name als Id verwendet, * weil der Name eines Plugins eindeutig sein sollte. * Es ist natürlich auch möglich einen anderen Text zu wählen, * Zum Beispiel um mehrere verschiedene Einträge pro Plugin * zu erzeugen. */ /* in einem Plugin ein Mircosummary lesen */ $microsummary = Microsummary::get($this->name); /* in einem Plugin ein Mircosummary "veröffentlichen", * damit der Browser dieses beim Öffnen der Seite findet */ Microsummary::publish($this->name); /* Aufruf der Microsummary im Browser */ index.php?action=get_microsummary&target=guestbook /* Zum Testen muss die URL vervollständigt und im Browser in die Adresszeile eingegeben werden. * Das Argument "target" bezeichnet hier die Id der anzuzeigenden Microsummary. */ ?>
"RSS-Feeds" sind elektronische, (meist) automatisch generierte und aktualisierte Verzeichnisse, welche verschiedene Informationen bereithalten können. Diese Verzeichnisse kann ein Besucher mit Programmen, die "RSS-Reader" genannt werden, lesen. In modernen Browsern ist diese Funktion bereits eingebaut, so dass der Besucher keine zusätzliche Software mehr benötigt.
Beispiele für RSS-Feeds:
Das Yana Framework unterstützt das Erzeugen von RSS-Feeds für Ihre Anwendungen. Dazu können Sie die für Sie vorbereiteten Klassen "RSS", bzw. "RSSitem" benutzen. Im Folgenden einige Beispiele.
<?php /* Um in einem Plugin einen RSS-Feed zu erzeugen, legen Sie eine neue Funktion an. (Den Namen bitte Ihren Wünschen entsprechend ändern, er muss eindeutig sein.) */ function mein_rss_feed($ARGS) { $rss = new RSS(); // einen Titel und Beschreibung festlegen $rss->title = 'Max Muster\'s Neuigkeiten'; $rss->description = 'das ist mein RSS-Feed zu meiner Homepage'; // einen Eintrag erzeugen $item = new RSSitem(); $item->title = '1. Eintrag'; $item->link = 'http://beliebige.url'; $item->description = 'Ein kurzer Text, welcher den Inhalt beschreibt, oder ein Textauszug.'; // den Eintrag zum RSS-Feed hinzufügen $rss->addItem($item); // ein 2. Eintrag $item = new RSSitem(); $item->title = 'noch ein Eintrag'; $item->link = 'http://beliebige.andere.url'; $item->description = 'zweite Beschreibung'; $rss->addItem($item); // so geben Sie den RSS-Feed an den Browser aus print utf8_encode($rss->toString()); exit(0); } /* Sie können einen Link auf Ihren RSS-Feed in der Anwendung anzeigen lassen. Dazu benutzen Sie die Funktion RSS::publish() und den Namen der Funktion, welche Ihren RSS-Feed erzeugt. Tipp: Am Einfachsten ist es, den Link über den Konstruktor Ihres Plugins einzubinden.*/ function plugin_mein_test($name) { RSS::publish('mein_rss_feed'); // hier kann weiterer Quellcode folgen } ?>
Das folgende Tutorial wird demonstrieren, wie Sie eigene Plugins für das Yana Framework schreiben können. Dazu wird im Verlauf des Textes ein einfaches Plugin zum Schreiben von so genannten "Blogs" erstellt. Den Quellcode finden Sie als Anhang am Ende dieses Tutorials.
Der Zeitaufwand um alle Schritte nachzuvollziehen beläuft sich auf etwa 1 Stunde. Literaturhinweise zu thematisch verwandten Artikeln finden Sie jeweils am Ende eines Abschnitts. Falls Sie einen Abschnitt überspringen wollen, finden Sie zudem fertige Quellcodeauszüge, welche Sie kopieren können.
Bevor Sie mit diesem Tutorial beginnen, sollten Sie sicherstellen, dass Sie einige Vorbereitungen abgeschlossen haben, da Sie andernfalls an eine Stelle gelangen könnten, an der Sie das Tutorial nicht fortsetzen können.
Zunächst benötigen Sie Zugang zu einem Webserver mit PHP. Vorzugsweise sollte dies eine lokale Installation sein, da dadurch die Arbeit vereinfacht wird. Allerdings genügt auch ein Zugang zu einem Webserver via FTP.
Außerdem sollten Sie vorab das Yana Framework bereits installiert haben und als Administrator darauf zugreifen können. Sie müssen außerdem das "Software Development Kit" für das Yana Framework installiert und aktiviert haben.
Optional empfehle ich Ihnen, einen geeigneten Editor für das Framework, wahlweise die Software " PSPad " oder alternativ " ConTEXT ", zu installieren. Für diese beiden Editoren stehen Syntax-Highlighter und Code-Templates zur Verfügung. Lesen Sie vorab das Kapitel über Editoren, falls Sie eine Installationsanleitung wünschen. Für den Zweck dieses Tutorials, wird die Software "PSPad" verwendet.
Grundlegende Kenntnisse im Aufbau und der Funktion von PHP und MySQL-Datenbanken werden vorausgesetzt.
Datenbanken werden im Yana Framework repräsentiert durch so genannte "Datenbankschemata". Diese Schemata sind Beschreibungen der Struktur einer Datenbank. Das heißt, der enthaltenen Tabellen, deren Spalten, Indexes und Constraints. Diese Informationen werden in Dateien gespeichert. Diese Dateien werden "Datenbankstrukturdateien" genannt und im Verzeichnis "config/db" des Frameworks abgelegt.
Darüber hinaus - und das unterscheidet das Yana Framework grundlegend von anderen Frameworks - enthalten diese Dateien auch die Beschreibung der Semantik einer Datenbank. Das heißt, in welchem Kontext eine Spalte sichtbar oder unsichtbar sein sollte, wie die Informationen für den Nutzer dargestellt werden sollen oder welche Beschriftung die Spalte haben sollte.
Sie benötigen zum Erstellen einer Datenbank für das Yana Framework also kein teures Modellierungswerkzeug und keine SQL-Kenntnisse, sondern lediglich einen einfachen Texteditor.
Um eine neue Datenbank zu erzeugen, öffnen Sie zunächst eine leere Textdatei in PSPad. Stellen die Syntax der Datei auf "Yana Framework" um (sollten Sie den Highlighter und die Code-Templates noch nicht installiert haben, lesen Sie dazu das Kapitel "Editoren für das Yana Framework" ).
Die neue Datenbank wird eine Tabelle "blog" enthalten, welche die Einträge eines Weblogs speichern soll. Jeder Eintrag wird eine eindeutige Id (Primärschlüssel) besitzen, den Namen des Autors, Datum der Erstellung, einen Titel und einen Text.
Bei der Erstellung der Datenbank können Ihnen Code-Templates helfen. Geben Sie den Text "db" ein und drücken Sie die Tasten <STRG> + <SPACE> gleichzeitig. Dadurch wird die Liste der Vorlagen geöffnet. Diese Liste hat zwei Spalten: links in Fettdruck ein "Shortcut", den Sie eingeben können um das Template direkt aufzurufen (wie in diesem Fall "db") und rechts eine Beschreibung des Templates.
Abbildung: Einfügen von Code-Templates
Wählen Sie die Vorlage "database definition" und drücken Sie <ENTER>. Das Dokument sollte nun so aussehen wie in folgender Abbildung:
Abbildung: Rumpf der Datenbank
Fügen Sie nun eine Tabelle ein. Drücken Sie dazu <STRG> + <SPACE> und wählen Sie den Eintrag "table definition" (Shortcut "tbl"). Benennen Sie die Tabelle indem Sie den Tabellennamen als Bezeichnung des öffnenden und schließenden Tags einsetzen. In diesem Tutorial soll die Tabelle den Namen "blog" erhalten.
Abbildung: Tabelle "blog"
Fügen Sie der Tabelle nun einen Primärschlüssel hinzu. Eine Tabelle kann stets nur 1 Primärschlüssel besitzen. Der Primärschlüssel muss stets aus genau einer Spalte bestehen und diese Spalte muss vom Typ "integer", "float" oder "string" sein. So genannte "compound primary keys" werden nicht unterstützt.
Um eine Spalte hinzuzufügen, klicken Sie in den Container "CONTENT" der Tabelle und fügen Sie das Code Template "primary key" ein (Shortcut "id"). Nennen Sie die Spalte "blog_id".
Um zu definieren, dass die Spalte "blog_id" ein Primärschlüssel ist, müssen Sie den Namen der Spalte im Feld "PRIMARY_KEY" eintragen.
Haben Sie diese Schritte erfolgreich durchgeführt, sollte Ihre Datei wie folgt aussehen:
Abbildung: Einfügen des Primärschlüssels
Auf die gleiche Weise fügen Sie nun noch eine Spalte vom Typ "string" für den Titel ein, eine Spalte vom Typ "text" für den Text des Eintrags. Eine Spalte vom Typ "time" für das Erstellungsdatum und eine weitere Spalte vom Typ "string" für den Namen des Autors.
Der Quellcode sollte nun wie folgt aussehen:
<USE_STRICT>true</USE_STRICT>
<READONLY>false</READONLY>
<TABLES>
<blog>
<PRIMARY_KEY>blog_id</PRIMARY_KEY>
<CONTENT>
<blog_id>
<TYPE>integer</TYPE>
<LENGTH>8</LENGTH>
<REQUIRED>AUTO</REQUIRED>
<DISPLAY>
<HIDDEN>true</HIDDEN>
</DISPLAY>
</blog_id>
<blog_title>
<TYPE>string</TYPE>
<LENGTH>255</LENGTH>
<DESCRIPTION>Titel</DESCRIPTION>
</blog_title>
<blog_text>
<TYPE>text</TYPE>
<LENGTH>3000</LENGTH>
<REQUIRED>true</REQUIRED>
<DESCRIPTION>Text</DESCRIPTION>
</blog_text>
<blog_created>
<TYPE>time</TYPE>
<REQUIRED>AUTO</REQUIRED>
<DESCRIPTION>Datum</DESCRIPTION>
</blog_created>
<blog_author>
<TYPE>string</TYPE>
<LENGTH>255</LENGTH>
<DESCRIPTION>Autor</DESCRIPTION>
</blog_author>
</CONTENT>
</blog>
</TABLES>
Vergleichen Sie den obigen Quellcode mit Ihrem Ergebnis.
Die Eigenschaft " TYPE " gibt den Typ der Spalte an, " DESCRIPTION " eine Beschriftung der Spalte für den Nutzer. Die Eigenschaft "LENGTH" gibt an wie groß der Inhalt für das Feld sein darf. Bei Spalten vom Typ "string" (in MySQL werden diese als "VARCHAR" umgesetzt) ist dies die Anzahl der Zeichen, welche der Eintrag maximal lang sein darf.
Die Eigenschaft " REQUIRED " gibt an, ob ein Wert zwingend erforderlich ist. Sie kann drei Werte annehmen: "true", "false" und "AUTO". Dabei bedeutet: "true" = ein Pflichtfeld, "false" = eine optionale Angabe und "AUTO" = falls der Nutzer keine Angaben macht, wird der Wert automatisch erzeugt.
Oder anders formuliert: die Eigenschaft "REQUIRED" gibt an, ob eine Spalte "Nullable" ist. Hat "REQUIRED" den Wert "true", wird die Spalte in MySQL zu "NOT NULL" umgesetzt und umgekehrt.
Wenn Sie zum Beispiel den Wert "AUTO" auf eine Spalte vom Typ "integer" anwenden, so erhalten Sie in MySQL eine Spalte, welche das Autoinkrementfeature verwendet. Die Spalte "blog_id" in obigem Beispiel ist somit eine Spalte mit Autoinkrement. (In MSSQL und DB2 wird dies als "Identity", als "Sequenz" in PostgreSQL und in Oracle als Trigger realisiert). Der Wert "AUTO" auf einer Spalte vom Typ "time" bewirkt, dass die aktuelle Zeit als Wert eingetragen wird.
Eine Eigenschaft, welche Sie in dem obigen Beispiel bisher noch nicht verwendet haben, heißt " DEFAULT ". Diese kann verwendet werden, um einen "Defaultwert" anzugeben, welcher automatisch verwendet werden soll, falls der Nutzer keine anderen Angaben macht.
Zum Abschluss, die Eigenschaft " DISPLAY ". Diese Eigenschaft hat keine Entsprechung in SQL. Sie dient der Steuerung der Darstellung der Spalte im Framework. Sie gibt an, in welchen Formularen die Spalte: sichtbar, sichtbar und editierbar, oder nicht sichtbar sein soll. Dabei wird unterschieden zwischen Formularen zum: Anzeigen, Suchen, Erstellen und Editieren von Datensätzen in der Tabelle.
Die obige Tabelle sollte noch um einige Angaben ergänzt werden.
Beispielsweise sollte festgelegt werden, dass die Spalten "blog_title" (Titel) und "blog_text" (Text) immer ausgefüllt werden müssen. Dazu ergänzen Sie die Eigenschaft "REQUIRED" mit dem Wert "true" (Shortcut "req").
Die Angabe zum Erstellungsdatum wird automatisch eingefügt. Sie sollte daher beim Schreiben des Eintrags für den Nutzer nicht sichtbar sein und nicht nachträglich editiert werden können. Fügen Sie für die Spalte "blog_created" (Datum) eine Eigenschaft "DISPLAY" ein (Shortcut "disp"). Setzen Sie die Werte "HIDDEN.NEW" und "READONLY.EDIT" auf "true". Setzen Sie alle anderen Werte auf "false".
Sie können selbstverständlich mehrere Blogs in einer Tabelle speichern. Dazu benötigen Sie eine zusätzliche Spalte, welche identifiziert, zu welchem Blog ein Eintrag gehört. Dies kann zum Beispiel nützlich sein, falls Sie mehrere Webseiten haben und pro Webseite einen eigenen Blog speichern möchten.
Die Unterscheidung in mehrere Blogs und die Zuordnung zu einzelnen Webseiten müssen Sie nicht von Hand programmieren. Das Framework besitzt für diesen Zweck ein vorbereitetes Template.
Fügen Sie zunächst eine neue Spalte vom Typ "profile" ein (Shortcut "pid"). Die Spalte sollte den Namen "profile_id" haben. Anschließend fügen Sie für die Tabelle, unter der Eigenschaft "PRIMARY_KEY" die Eigenschaft "PROFILE_KEY" ein (Shortcut "prf") und setzen den Wert dieser Eigenschaft auf den Namen der Spalte: "profile_id".
Vergleichen Sie Ihr Ergebnis mit dem folgenden Quellcode.
<USE_STRICT>true</USE_STRICT>
<READONLY>false</READONLY>
<TABLES>
<blog>
<PRIMARY_KEY>blog_id</PRIMARY_KEY>
<PROFILE_KEY>profile_id</PROFILE_KEY>
<CONTENT>
<blog_id>
<TYPE>integer</TYPE>
<LENGTH>8</LENGTH>
<REQUIRED>AUTO</REQUIRED>
<DISPLAY>
<HIDDEN>true</HIDDEN>
</DISPLAY>
</blog_id>
<blog_title>
<TYPE>string</TYPE>
<LENGTH>255</LENGTH>
<DESCRIPTION>Titel</DESCRIPTION>
<REQUIRED>true</REQUIRED>
</blog_title>
<blog_text>
<TYPE>text</TYPE>
<LENGTH>3000</LENGTH>
<REQUIRED>true</REQUIRED>
<DESCRIPTION>Text</DESCRIPTION>
<REQUIRED>true</REQUIRED>
</blog_text>
<blog_created>
<TYPE>time</TYPE>
<REQUIRED>AUTO</REQUIRED>
<DESCRIPTION>Datum</DESCRIPTION>
<DISPLAY>
<HIDDEN>
<NEW>true</NEW>
</HIDDEN>
<READONLY>
<EDIT>true</EDIT>
</READONLY>
</DISPLAY>
</blog_created>
<blog_author>
<TYPE>string</TYPE>
<LENGTH>255</LENGTH>
<DESCRIPTION>Autor</DESCRIPTION>
</blog_author>
<profile_id>
<TYPE>profile</TYPE>
<LENGTH>128</LENGTH>
<REQUIRED>AUTO</REQUIRED>
<DISPLAY>
<HIDDEN>true</HIDDEN>
</DISPLAY>
</profile_id>
</CONTENT>
</blog>
</TABLES>
Damit ist das Erstellen der Datenbank abgeschlossen. Speichern Sie Ihre Änderungen unter der Datei "blog.config" und schließen Sie das Programm.
Falls Sie sich tiefer mit den in diesem Abschnitt behandelten Themen beschäftigen wollen, finden Sie Anleitung in folgenden Artikeln:
Der folgende Abschnitt wird sich mit der Erstellung des Programmcodes beschäftigen.
Sofern Sie das Tutorial bis zu diesem Punkt nachvollzogen haben, besitzen Sie zu diesem Zeitpunkt bereits eine einfache Datenbank. Um diese jedoch "zum Leben zu erwecken", fehlt Ihnen noch die Business-Logik der eigentlichen Anwendung, sowie eine Oberfläche zur Darstellung von Formularen und Nutzereingaben. Beides werden Sie im folgenden Abschnitt erstellen.
Öffnen Sie nun die Startseite des Yana Frameworks in einem javascriptfähigen Webbrowser, beispielsweise Firefox 2.0. Melden Sie sich über den Link "Login" am System als "Administrator" an. Sie werden Administratorrechte benötigen, um mit dem nächsten Schritt fortfahren zu können.
Öffnen Sie auf der Startseite des Frameworks den Link "Software Development Kit". Sollten Sie dieses bis jetzt noch nicht installiert, bzw. aktiviert haben, holen Sie dies bitte jetzt nach. Lesen Sie dazu das Kapitel "Plugins und Anwendungen erstellen".
Haben Sie den Link geöffnet, sollten Sie folgendes Formular sehen können.
Abbildung: Startseite des "Software Development Kit"
Zunächst können Sie einen Namen (zum Beispiel "mein Blog"), eine beliebige Beschreibung und ein Logo für Ihr Plugin auswählen. Unter der Registerkarte "Autor" können Sie Angaben zu Ihrem Namen, Ihrer Webseite und Kontaktadresse machen.
Auf der Seite "sonstige Daten" können Sie den "Typ der Anwendung" auf den Wert "primary" ändern. Dadurch wird das Plugin als "Hauptprogramm" deklariert. Diese Angabe ist optional und keine Pflicht, kann jedoch die Performance erhöhen.
Abbildung: Setzen des Typs der Anwendung
Klicken Sie anschließend direkt auf die Registerkarte "Datenbank".
Abbildung: Auswählen der Datenbankstrukturdatei
Klicken Sie auf die Schaltfläche "Durchsuchen". Wählen Sie als Quelle die von Ihnen erstellte Datei "blog.config" aus.
Weitere Angaben zu Ihrem Plugin sind an dieser Stelle nicht erforderlich. Klicken Sie auf die Schaltfläche "Fertigstellen", um den Quellcode und die Eingabeoberflächen für Ihr erstes Plugin generieren zu lassen. Anschließend können Sie das gerade erstellte Plugin sofort ausprobieren.
Öffnen Sie das Administrationsmenü im Expertenmodus. Klicken Sie im Menü "Plugins" auf den Link "Liste neu laden". Anschließend wählen Sie aus der Liste der Plugins den Namen Ihres Plugins aus und aktivieren Sie dieses durch anklicken der Checkbox links neben dem Namen. Klicken Sie auf die Schalfläche "Änderungen speichern" unterhalb des Menüs.
Zum Vergleich zeigt die folgende Abbildung das oben genannte Menü.
Abbildung: Aktivieren des Plugins
Achtung!
Falls Sie die Datenbankunterstützung NICHT aktiviert haben, müssen Sie
diesen Schritt NICHT durchführen.
Falls Sie die Datenbankunterstützung aktiviert haben und beispielsweise
eine MySQL-Datenbank zum Speichern der Einträge benutzen, dann müssen
Sie die Tabellen für das Plugin zuerst installieren. Öffnen Sie dazu
das Menü "Datenbank Setup" und wählen Sie aus dem Dropdownmenü den
Eintrag "markierte Datenbanken installieren". Es erscheint eine
Auswahlliste. Aktivieren Sie nur den Eintrag der Datenbank Ihres
Plugins und klicken Sie auf die Schaltfläche "Änderungen speichern".
Siehe folgende Abbildung:
Abbildung: die Tabelle des Plugins auf der Datenbank installieren
Anschließend wechseln Sie zurück auf die Sitemap des Frameworks. Dort sollte nun der Name Ihres Plugins im Auswahlmenü auftauchen. Klicken Sie auf diesen Link. Sie sollten nun die Startseite Ihrer Anwendung sehen, wie die folgende Abbildung zeigt.
Abbildung: Startseite des neuen Plugins
Der Text "keine Einträge gefunden" zeigt an, dass zur Zeit keine Einträge in Ihrem Blog gespeichert sind. Klicken Sie auf den Link "new" um einen neuen Eintrag zu erstellen.
Abbildung: Erstellen eines neuen Eintrags
Anschließend sollte Ihnen folgende Übersichtsseite angezeigt werden. (Die Abbildung zeigt das Formular mit zwei Einträgen)
Abbildung: Übersichtsdarstellung
Es gibt weitere, alternative Ansichten. Am Ende der Tabelle finden Sie eine Liste mit 4 verschiedenen Layouts. Sie können sich entscheiden, welche Darstellung Ihnen besser gefällt.
Abbildung: Detaildarstellung
Klicken Sie auf den Link "bearbeiten" um Einträge zu editieren. Sie sollten das folgende Formular angezeigt bekommen.
Abbildung: Editieren von Einträgen
Durch Anklicken der Spalten, ändern Sie die Sortierung. Zeilen, die Sie ändern möchten, markieren Sie in der linken Spalte durch Anklicken der Checkbox. In der letzten Zeile befinden sich leere Felder, welche Sie benutzen können um schnell einen neuen Eintrag zu erstellen.
Dieses Formular verfügt über ein besonderes Feature. Wenn Sie aus dem Menü "Einträge pro Seite" den Wert "1" wählen, vergrößert sich die Ansicht des Editors für den jeweiligen Eintrag, was größeren Komfort bei der Eingabe der Daten ermöglicht, wie die folgende Abbildung zeigt.
Abbildung: Editieren eines einzelnen Eintrags
Falls Sie dies wünschen, können Sie die weiteren Funktionen Ihres neuen Plugins an dieser Stelle ebenfalls probieren.
Wie Sie sehen konnten, hat das Yana Framework Ihnen bereits einen großen Teil der notwendigen Arbeiten abgenommen. Allerdings gibt es sicher einige Details, welche Sie nachträglich Ihren Bedürfnissen anpassen möchten. Mit diesen Anpassungen wird sich der folgende Abschnitt des Tutorials beschäftigen.
Im folgenden Abschnitt werden die Definitionsdatei von Plugins und Templates vorgestellt. Es wird demonstriert, wie diese Dateien editiert werden können, um sie persönlichen Bedürfnissen anzupassen.
Als ersten Schritt soll demonstriert werden, wie Sie Smilies (Emoticons) und embedded Tags (zum Formatieren von Text) einfügen können. Öffnen Sie dazu die Datei "skins/default/blog/blog_default_new_blog.html" in PSPad. Beachten Sie dabei, dass Sie den Text "blog" durch den Namen Ihres Projektes ersetzen müssen. Wählen Sie den Highlighter "Yana Framework Templates" aus der Liste der verfügbaren Highlighter.
Zum Vergleich dazu siehe auch die folgende Abbildung:
Abbildung: Darstellung des Templates in PSPad
Der Aufruf der Funktion "import" lädt das Baummenü aus der Datei "index.html". Die Funktion "create" ruft den Formulargenerator des Yana Frameworks auf, um das Formular zum Erzeugen eines neuen Eintrags zu generieren.
Eine Erläuterung der Funktion "create" finden Sie in der Referenz der Template-Funktionen und -Modifier.
Auch in Templates können Sie wiederum Code-Templates verwenden. Fügen Sie nun hinter dem Funktionsaufruf "create" einen Aufruf der Funktion "embeddedTags" (Shortcut "embTag"). Argumente brauchen Sie für diese Funktion zunächst nicht angeben.
Eine Erläuterung der Funktion "embeddedTags" finden Sie in der Referenz der Template-Funktionen und -Modifier.
Der Quellcode sollte nun wie folgt aussehen:
<!-- Begin: menu -->
<div style="width: 250px; overflow: auto; float: left;">
[%import file="index.html"%]
</div>
<!-- End: menu -->
<!-- Begin: content -->
<div style="margin-left: 260px;">
[%create
template="new"
file="blog"
table="blog"
where=$WHERE
titles=""
on_edit="blog_write_edit_blog"
on_delete="blog_write_delete_blog"
on_new="blog_write_new_blog"
on_search="blog_read_search_blog"
on_download="blog_blog_download"
sort=$SORT
desc=$DESC
page=$PAGE
entries=$ENTRIES %]
[%embeddedTags%]
</div>
<!-- End: content -->
<!-- Begin: foot -->
<div style="clear: both;">
<!-- your text here -->
</div>
<!-- End: foot -->
Vergleichen Sie den obigen Quellcode mit Ihrem Ergebnis.
Wenn Sie die Seite Ihres Plugins nun erneut im Browser aufrufen, präsentiert diese sich wie folgt.
Abbildung: Darstellung im Browser (Firefox 3)
Es ist angebracht, diese Darstellung optisch anzupassen. Da es dafür verschiedene Lösungen gibt und Geschmäcker bekanntlich verschieden sind, dazu folgender Vorschlag.
<fieldset>
<legend style="font-size: 12px; font-weight: bold;">Text formatieren:</legend>
[%embeddedTags show="b,i,u,|,h,emp,code,hide,|,small,big,|,img,url,mail,-,mark,color,smilies"%]
</fieldset>
Falls die Tags "fieldset" und "legend" Ihnen bis jetzt noch
nicht vertraut waren: Diese Tags erzeugen Unterabschnitte innerhalb von
Formularen. Der Tag "legend" legt eine Beschriftung fest.
Dargestellt werden "Fieldsets" standardmäßig als umrahmte Blockabschnitte.
Der Text innerhalb des Tags "Legend" wird dabei innerhalb der Umrandung
dargestellt.
Zudem demonstriert dieser Quellcode die Verwendung der
Argumente der Funktion "embeddedTags". Achten Sie besonders auf das Argument
"show" der Funktion "embeddedTags".
Diese akzeptiert die beiden besonderen Werte "|" und "-". Dabei erzeugt "|"
einen senkrechten Trennstrich und "-" kann verwendet werden, um einen
Zeilenumbruch zu erzeugen.
Abschließend soll oberhalb der beiden Fieldsets eine Vorschau auf den neuen Blogeintrag erzeugt werden (verwenden Sie dazu den Shortcut "preview"). Sie können das Template übernehmen, die Parameter "height" und "width" werden nicht benötigt und können entfernt werden.
Der daraus resultierende Quellcode sieht wie folgt aus:
<!-- Begin: menu -->
<div style="width: 250px; overflow: auto; float: left;">
[%import file="index.html"%]
</div>
<!-- End: menu -->
<!-- Begin: content -->
<div style="margin-left: 260px;">
[%create
template="new"
file="blog"
table="blog"
where=$WHERE
titles=""
on_edit="blog_write_edit_blog"
on_delete="blog_write_delete_blog"
on_new="blog_write_new_blog"
on_search="blog_read_search_blog"
on_download="blog_blog_download"
sort=$SORT
desc=$DESC
page=$PAGE
entries=$ENTRIES %]
[%preview%]
<fieldset>
<legend style="font-size: 12px; font-weight: bold;">Text formatieren:</legend>
[%embeddedTags show="b,i,u,|,h,emp,code,hide,|,small,big,|,img,url,mail,-,mark,color,smilies"%]
</fieldset>
</div>
<!-- End: content -->
<!-- Begin: foot -->
<div style="clear: both;">
<!-- your text here -->
</div>
<!-- End: foot -->
Als Quelle verwendet die Vorschau automatisch das zuletzt aktivierte Textarea-Feld der Seite. Die Darstellung wird via AJAX vom Server geholt und direkt angezeigt, ohne das Formular neu laden zu müssen.
Im Browser präsentiert sich das Ergebnis wie folgt:
Abbildung: Darstellung im Browser (Firefox 3)
Klicken Sie noch einmal auf den Menüpunkt "anzeigen". Beachten Sie die Reihenfolge der Einträge. Per Voreinstellung sind diese aufsteigend nach dem Primärschlüssel sortiert. Dies ist für einen Blog in der Regel nicht erwünscht. Stattdessen sollten die Einträge absteigend nach dem Datum ihrer Erstellung sortiert sein. Um dies zu korrigieren, öffnen Sie nun die Datei "skins/default/blog/blog_read_read_blog.html" in PSPad. Beachten Sie dabei, dass Sie den Text "blog" durch den Namen Ihres Projektes ersetzen müssen. Wählen Sie den Highlighter "Yana Framework Templates" aus der Liste der verfügbaren Highlighter.
Wie bereits erwähnt, dient die Funktion "create" zum Aufrufen des Formulargenerators. Dieser nimmt einige Parameter, mit welchen die Ausgabe gesteuert wird. Setzen Sie den Parameter "sort" auf "blog_created" um nach der Spalte "blog_created" der Tabelle "blog" zu sortieren, welche das Datum der Erstellung der Einträge enthält. Setzen Sie den Parameter "desc" auf den Wert "true", was bewirkt, dass absteigend (eng. "descending") sortiert wird.
Beachten Sie, dass der Parameter "where" auf die Variable "$WHERE" gesetzt ist. Dies wird zu einem späteren Abschnitt dieses Tutorials eine wichtige Rolle spielen.
Der folgende Quellcodeauszug illustriert das Ergebnis.
<!-- Begin: menu -->
<div style="width: 250px; overflow: auto; float: left;">
[%import file="index.html"%]
</div>
<!-- End: menu -->
<!-- Begin: content -->
<div style="margin-left: 260px;">
[%create
template="view"
layout=3
file="blog"
table="blog"
where=$WHERE
titles=""
on_edit="blog_write_edit_blog"
on_delete="blog_write_delete_blog"
on_new="blog_write_new_blog"
on_search="blog_read_search_blog"
on_download="blog_blog_download"
sort="blog_created"
desc=$DESC
page=$PAGE
entries=$ENTRIES %]
</div>
<!-- End: content -->
<!-- Begin: foot -->
<div style="clear: both;">
<!-- your text here -->
</div>
<!-- End: foot -->
Vergleichen Sie den obigen Quellcode mit Ihrem Ergebnis.
Als nächstes soll das Baummenü so angepasst werden, dass die Einträge "neu" und "Über dieses Plugin ..." nur Nutzern angezeigt werden, die am System angemeldet sind und über ein ausreichend hohes Sicherheitslevel verfügen. Außerdem möchten Sie möglicherweise die Beschriftung der Optionen ändern.
Der Quellcode der Datei sieht zunächst wie folgt aus:
<ul class="menu root" id="_menu">
<li class="menu">
<div onclick="yanaMenu(this)">blog</div>
<ul class="menu">
<!-- [%if $PERMISSION >= 75%] -->
<li class="entry"><a href=[%"action=mein_plugin_read_edit_blog"|href%]>[%$LANGUAGE.MENU.EDIT%]</a></li>
<!-- [%/if%] -->
<!-- [%if $PERMISSION >= 0%] -->
<li class="entry"><a href=[%"action=mein_plugin_default_new_blog"|href%]>[%$LANGUAGE.MENU.NEW%]</a></li>
<!-- [%/if%] -->
<!-- [%if $PERMISSION >= 0%] -->
<li class="entry"><a href=[%"action=mein_plugin_read_search_blog"|href%]>[%$LANGUAGE.MENU.SEARCH%]</a></li>
<!-- [%/if%] -->
<!-- [%if $PERMISSION >= 0%] -->
<li class="entry"><a href=[%"action=mein_plugin_read_read_blog"|href%]>[%$LANGUAGE.MENU.VIEW%]</a></li>
<!-- [%/if%] -->
</ul>
</li>
<li class="entry"><a href=[%"action=about&target=mein_plugin&type=plugin"|href%]>[%$LANGUAGE.ABOUT%] ...</a></li>
</ul>
Dass die IF-Verzweigungen hier in Kommentare eingebettet sind dient der besseren Lesbarkeit des Codes und der Darstellung des Templates im Browser. Für das Template selbst macht es keinen Unterschied, ob Sie diese Kommentare verwenden wollen oder nicht.
Die Variable $PERMISSION enthält die Sicherheitsstufe Ihres Besuchers. Gäste erhalten in der Voreinstellung automatisch die Sicherheitsstufe "0", Administratoren die Stufe "100". Dazwischen können weitere Stufen vergeben werden. Voreingestellt ist für Moderatoren beispielsweise die Stufe "30". Sie können diese Variable verwenden um zu entscheiden, wann bestimmte Menüpunkte angezeigt werden sollen und wann nicht. Ändern Sie den Wert für "Permission" für die Optionen "new" und "about" beispielsweise auf ">= 30" (der Wert 30 steht per Default für die Gruppe der Moderatoren).
Da die Variable $PERMISSION stets einen Wert >= 0 hat, können Sie die entsprechenden Prüfungen zum Zweck besserer Performance auch entfernen.
Vergleichen Sie Ihr Ergebnis mit dem folgenden Code.
<ul class="menu root" id="_menu">
<li class="menu">
<div onclick="yanaMenu(this)">blog</div>
<ul class="menu">
<!-- [%if $PERMISSION >= 75%] -->
<li class="entry"><a href=[%"action=mein_plugin_read_edit_blog"|href%]>[%$LANGUAGE.MENU.EDIT%]</a></li>
<!-- [%/if%] -->
<!-- [%if $PERMISSION >= 30%] -->
<li class="entry"><a href=[%"action=mein_plugin_default_new_blog"|href%]>[%$LANGUAGE.MENU.NEW%]</a></li>
<!-- [%/if%] -->
<li class="entry"><a href=[%"action=mein_plugin_read_search_blog"|href%]>[%$LANGUAGE.MENU.SEARCH%]</a></li>
<li class="entry"><a href=[%"action=mein_plugin_read_read_blog"|href%]>[%$LANGUAGE.MENU.VIEW%]</a></li>
</ul>
</li>
<li class="entry"><a href=[%"action=about&target=mein_plugin&type=plugin"|href%]>[%$LANGUAGE.ABOUT%] ...</a></li>
</ul>
Wie Sie vielleicht bereits vermutet haben, war dies lediglich der erste Schritt. Zwar ist der Menüpunkt zum Anlegen eines neuen Eintrags nun für Gäste ausgeblendet, allerdings ist er durch Eingabe der richtigen URL in die Adresszeile des Browsers immer noch aufrufbar. Ein geschickter Nutzer könnte sich diesen Umstand zunutze machen, um die Prüfung seines Sicherheitslevels zu umgehen. Der folgende Abschnitt wird demonstrieren, wie Sie die Konfigurationsdatei Ihres Plugins editieren können, um dies zu verhindern.
Von HTML-Templates nun zurück zu Konfigurationsdateien. Öffnen Sie die Datei "plugins/blog.config" in PSPad (beachten Sie, dass sie den Namen "blog" durch den Namen Ihres Plugins ersetzen müssen). Wählen Sie den Highlighter "Yana Framework" aus.
Abbildung: Darstellung der Konfigurationsdatei in PSPad
Der Container "INFO" enthält den Header der Konfigurationsdatei. Dieser Block kann, je nachdem welche Eingaben beim Erstellen des Plugins gemacht wurden, in Ihrem Fall geringfügig anders aussehen.
Zunächst einmal sehen Sie hier unter dem Eintrag "START" die gewählte Startseite des Plugins (blog_read_read_blog). Ihr Wert entspricht dem Wert des Arguments "action", welches an die URL angehängt wird. Der Wert identifiziert eindeutig das Plugin und die Aktion, welche das Plugin ausführen soll. Der Name wurde automatisch generiert. Falls Sie eine andere Seite als Startseite wünschen, rufen Sie die diese Seite in Ihrem Browser auf. Schauen Sie in der Adressleiste des Browsers nach dem Wert des Arguments "action" und kopieren Sie diesen Wert aus der Adressleiste in das Feld "START".
Der Container "INTERFACE" beschreibt alle Aktionen, welche Ihr Plugin verarbeiten kann. Für jede Aktion existiert ein Tag, welcher weitere Tags enthält, welche dessen Eigenschaften beschreiben. Die Namen wurden auch hier automatisch erstellt. Beachten Sie, dass diese Namen eindeutig sein müssen. Es ist folglich nicht sinnvoll, eine Aktion beispielsweise "insert" zu nennen, weil diese Bezeichnung vermutlich nicht eindeutig wäre.
Eine Erläuterung aller Tags dieser Konfigurationsdatei, sowie Codebeispiele, finden Sie im Kochbuch für Entwickler, Kapitel "Plugins editieren".
Im nächsten Schritt werden die Änderungen in der Datei "index.html" in der Konfigurationsdatei nachvollzogen, um ein Umgehen der Sicherheitsprüfung unmöglich zu machen.
Suchen Sie dazu zunächst in dem Dokument die Aktion "blog_default_new_blog" und setzen Sie im Feld "PERMISSION" den Wert auf "30", analog zur Datei "index.html". Wiederholen Sie dies für die Aktion "blog_write_new_blog". Zum Verständnis: Die Aktion "blog_default_new_blog" dient dem Anzeigen des Formulars, die Aktion "blog_write_new_blog" dient dem Speichern der Eingaben. Beide Aktionen gehören somit zum gleichen Formular und beide Werte müssen daher entsprechend geändert werden.
In der Datei "index.html" war die Option "list" enthalten, welche entfernt wurde (vergleichen Sie mit dem obigen Quellcode ). Diese Option war verbunden mit der Aktion "blog_read_read_blog". Suchen Sie nun diese Aktion und entfernen Sie diese.
Der Container "INTERFACE" sollte nun den folgenden Inhalt haben.
<INTERFACE>
<BLOG_READ_EDIT_BLOG>
<TYPE>read</TYPE>
<MODE>0</MODE>
<INSERT>BLOG_EDIT_BLOG</INSERT>
<PERMISSION>75</PERMISSION>
<ONSUCCESS>
<GOTO>blog_read_edit_blog</GOTO>
</ONSUCCESS>
<ONERROR>
<GOTO>blog_read_edit_blog</GOTO>
</ONERROR>
</BLOG_READ_EDIT_BLOG>
<BLOG_WRITE_EDIT_BLOG>
<TYPE>write</TYPE>
<MODE>0</MODE>
<TEMPLATE>MESSAGE</TEMPLATE>
<PERMISSION>75</PERMISSION>
<ONSUCCESS>
<GOTO>blog_read_edit_blog</GOTO>
</ONSUCCESS>
<ONERROR>
<GOTO>blog_read_edit_blog</GOTO>
</ONERROR>
</BLOG_WRITE_EDIT_BLOG>
<BLOG_WRITE_DELETE_BLOG>
<TYPE>write</TYPE>
<MODE>0</MODE>
<TEMPLATE>MESSAGE</TEMPLATE>
<PERMISSION>75</PERMISSION>
<ONSUCCESS>
<GOTO>blog_read_edit_blog</GOTO>
</ONSUCCESS>
<ONERROR>
<GOTO>blog_read_edit_blog</GOTO>
</ONERROR>
</BLOG_WRITE_DELETE_BLOG>
<BLOG_DEFAULT_NEW_BLOG>
<TYPE>default</TYPE>
<MODE>0</MODE>
<INSERT>BLOG_NEW_BLOG</INSERT>
<PERMISSION>30</PERMISSION>
<ONSUCCESS>
<GOTO>blog_default_new_blog</GOTO>
</ONSUCCESS>
<ONERROR>
<GOTO>blog_default_new_blog</GOTO>
</ONERROR>
</BLOG_DEFAULT_NEW_BLOG>
<BLOG_WRITE_NEW_BLOG>
<TYPE>write</TYPE>
<MODE>0</MODE>
<TEMPLATE>MESSAGE</TEMPLATE>
<PERMISSION>30</PERMISSION>
<ONSUCCESS>
<GOTO>blog_read_read_blog</GOTO>
</ONSUCCESS>
<ONERROR>
<GOTO>blog_default_new_blog</GOTO>
</ONERROR>
</BLOG_WRITE_NEW_BLOG>
<BLOG_READ_SEARCH_BLOG>
<TYPE>read</TYPE>
<MODE>0</MODE>
<INSERT>BLOG_SEARCH_BLOG</INSERT>
<PERMISSION>0</PERMISSION>
<ONSUCCESS>
<GOTO>blog_read_search_blog</GOTO>
</ONSUCCESS>
<ONERROR>
<GOTO>blog_read_search_blog</GOTO>
</ONERROR>
</BLOG_READ_SEARCH_BLOG>
<BLOG_READ_READ_BLOG>
<TYPE>read</TYPE>
<MODE>0</MODE>
<INSERT>BLOG_READ_BLOG</INSERT>
<PERMISSION>0</PERMISSION>
<ONSUCCESS>
<GOTO>blog_read_read_blog</GOTO>
</ONSUCCESS>
<ONERROR>
<GOTO>blog_read_read_blog</GOTO>
</ONERROR>
</BLOG_READ_READ_BLOG>
</INTERFACE>
Vergleichen Sie den obigen Quellcode mit Ihrem Ergebnis.
Der folgende Abschnitt soll Ihnen zeigen, wie Sie den PHP-Quellcode eines Plugins editieren können, um neue Funktionen hinzuzufügen oder existierende Funktionen Ihren Bedürfnissen anzupassen.
In diesem Abschnitt des Tutorials soll ein automatisch generierter RSS-Feed für die 10 neuesten Einträge des Blog implementiert werden. Das Tutorial führt Sie durch die verschiedenen Schritte der Erstellung.
Bevor Sie den PHP-Quellcode editieren, sollten Sie die neue Aktion in der Schnittstelle des Plugins eintragen. Nur dann kann diese auch über den Webbrowser aufgerufen werden. Dies ist dient einerseits der Performance und ist andererseits eine zusätzliche Sicherheitsmaßnahme, um das absichtliche Einschleusen fremden PHP-Codes in die Anwendung zu erschweren, das versehentliche Ausführen von Code zu verhindern und insgesamt Plugins damit sicherer zu machen.
Um diesen Schritt durchzuführen, öffnen Sie die Datei "plugins/blog.config" in PSPad (beachten Sie, dass sie den Namen "blog" durch den Namen Ihres Plugins ersetzen müssen). Wählen Sie den Highlighter "Yana Framework" aus.
Fügen Sie im Container "INTERFACE" eine neue Aktion ein (Shortcut "act"). Nennen Sie diese Aktion "blog_rss".
Ihr Quellcode sollte nun die folgende neue Aktion enthalten:
<INTERFACE>
[...]
<BLOG_RSS>
<TYPE>default</TYPE>
<MODE>0</MODE>
<PERMISSION>0</PERMISSION>
<TEMPLATE>INDEX</TEMPLATE>
<INSERT></INSERT>
<ONSUCCESS>
<TEXT>200</TEXT>
<GOTO></GOTO>
</ONSUCCESS>
<ONERROR>
<TEMPLATE>ALERT</TEMPLATE>
<TEXT>500</TEXT>
<GOTO></GOTO>
</ONERROR>
</BLOG_RSS>
[...]
</INTERFACE>
Nicht alle der automatisch eingefügten Felder werden benötigt. Passen Sie die Definition der Aktion nun wie folgt an:
<INTERFACE>
[...]
<BLOG_RSS>
<TYPE>read</TYPE>
<MODE>0</MODE>
<TEMPLATE>NULL</TEMPLATE>
<PERMISSION>0</PERMISSION>
</BLOG_RSS>
[...]
</INTERFACE>
Das Feld "TYPE" mit dem Wert "read" hat etwas mit dem Verhalten dieser Aktion zu tun. Dieser Typ drückt aus, dass diese Aktion lediglich lesend auf die Datenbank zugreifen muss. Diese Information kann für eine bessere Performance ausgenutzt werden.
Das Feld "MODE" mit dem Wert "0" sagt aus, dass der normale Betriebsmodus verwendet wird. (Mit dem Wert "1" startet das Programm für diese Aktion im "abgesicherten Modus").
Das Feld "PERMISSION" mit dem Wert "0" sagt aus, dass jeder Besucher auf diese Aktion zugreifen darf, ohne besondere Anforderungen an seinen Sicherheitslevel.
Das Feld "TEMPLATE" gibt an, welches Template für die Aktion
ausgewählt werden soll. Zwar ist es möglich das Template auch aus dem
PHP-Code heraus auszuwählen, allerdings ist die Verwendung dieses
Feldes in der Konfigurationsdatei übersichtlicher und einfacher.
Das hier ausgewählte Template "NULL" ist ein vordefinierter
Spezialwert. Er drückt aus, dass "kein Template" ausgewählt werden
soll. Dies ist in diesem Fall auch nicht erforderlich, weil die Ausgabe
durch einen automatischen RSS-Generator, ohne Template, erzeugt werden
wird.
Damit sind die Vorbereitungen abgeschlossen der folgende Abschnitt wird sich mit der Implementierung im PHP-Quellcode beschäftigen.
Öffnen Sie die Datei "plugins/blog/plugin.php" in PSPad (beachten Sie, dass sie den Namen "blog" durch den Namen Ihres Plugins ersetzen müssen). Wählen Sie den Highlighter "PHP" aus.
Fügen Sie in die Klasse "plugin_blog" eine neue Funktion mit dem Namen "blog_rss" ein. Um sich Schreibarbeit zu ersparen, können Sie folgende Vorlage verwenden.
<?php class plugin_blog extends plugin { // [...] /** * blog_rss * * returns bool(true) on success and bool(false) on error * * Type: read * Permission: 0 * Templates: NULL * * @access public * @return bool * @name plugin_blog::blog_rss() * @param array $ARGS array of params passed to the function */ function blog_rss ($ARGS) { } // [...] } ?>
Meine persönliche Empfehlung ist, Quellcode, denn Sie geschrieben haben, stets sofort zu dokumentieren, solange Ihnen der Aufbau und die Funktionsweise noch frisch im Gedächtnis sind. Dies hat zudem den unschätzbaren Vorteil, dass Sie sich dadurch zwangsweise noch einmal mit dem gerade beschriebenen Code beschäftigen müssen.
Um einen RSS-Feed der 10 aktuellsten Beiträge zu erstellen, müssen Sie zunächst erst einmal die 10 aktuellsten Beiträge aus der Datenbank laden. Dazu erstellen Sie ein Datenbankabfrage der Tabelle "blog". Durch Setzen der Limit-Klausel auf "10" limitieren Sie die Anzahl der Einträge des Resultsets auf maximal 10 Stück. Damit Sie tatsächlich die 10 neuesten Einträge erhalten, sortieren Sie die Einträge absteigend nach dem Datum Ihrer Erstellung. Das heißt nach der Spalte "blog_created". Verwenden Sie dazu "order_by" und "desc".
Der folgende Quellcode demonstriert diese Abfrage.
<?php /* get entries from database */ $query = array( 'key' => 'blog.*', 'order_by' => 'blog_created', 'desc' => true, 'limit' => 10 ); $rows = $this->database->get($query); ?>
Wie Sie in diesem Beispiel sehen, verfügt das Yana Framework über einen Query-Generator zum Erzeugen einfacher SQL-Statements. Sie benötigen also keinerlei SQL-Kenntnisse, um mit dem Yana Framework Abfragen auf einer Datenbank durchführen zu können. Das Mapping der tatsächlichen SQL-Statements auf die passende Syntax des eigentlichen DBMS erledigt das Framework ebenfalls automatisch.
Der Query-Generator ist außerdem in der Lage, automatisiert einfache Sicherheitsprüfungen durchzuführen, automatisches Quoting für Eingabewerte zu realisieren und SQL-Abfragen auf Plausibilität zu prüfen, ohne diese an die Datenbank zu senden. Dies reduziert zusätzlich das Risiko von SQL-Injections und erhöht dadurch die Sicherheit Ihrer Anwendung.
Das Resultset, hier $rows, besteht aus einem mehrdimensionalen, assoziativen Array. Jeder Eintrag entspricht einer Zeile. Jede Zeile wiederum hat jeweils einen Eintrag pro Spalte.
Ein Aufruf von var_export($rows) demonstriert dies. Die Ausgabe lautet wie folgt:
<?php array ( 2 => array ( 'BLOG_TITLE' => 'Testeintrag', 'BLOG_TEXT' => 'Das ist ein Test[br]Das ist ein Test[br]Das ist ein Test[br]Das ist ein Test', 'BLOG_AUTHOR' => 'Thomas Meyer', 'BLOG_CREATED' => '1173276511', 'PROFILE_ID' => 'default', 'BLOG_ID' => 2, ), 1 => array ( 'BLOG_TITLE' => 'Testeintrag', 'BLOG_TEXT' => 'Das ist ein Test.[br]Nur ein Test.[br][br]Neue Zeile.', 'BLOG_AUTHOR' => 'Thomas Meyer', 'BLOG_CREATED' => '1173276442', 'PROFILE_ID' => 'default', 'BLOG_ID' => 1, ), ) ?>
Wie Sie am Index des Arrays sehen, sind die Einträge in umgekehrter Reihenfolge, also absteigend, sortiert. Die Spaltennamen werden in Großbuchstaben ausgegeben.
Weitere Details und Codebeispiele finden Sie im Kochbuch für Entwickler, Kapitel Datenbanken und in der API-Dokumentation der Klasse "DbStream".
Zur Repräsentation von RSS-Feeds dient die Klasse "RSS". Um einen neuen Feed zu erzeugen, sollte als nächster Schritt eine Instanz dieser Klasse erzeugt werden.
<?php $rss = new RSS(); $rss->title = 'Blog'; $rss->description = 'the 10 most recent blog entries'; ?>
Den Titel und die Beschreibung des RSS-Feed können Sie frei wählen. Verwenden Sie dazu die Eigenschaften "title" und "description", wie im Beispiel gezeigt.
Anschließend ist für jeden Eintrag der Datenbank ein Eintrag im RSS-Feed zu erstellen. Ein Eintrag wird repräsentiert durch die Klasse "RSSitem". Um einen Eintrag zu erzeugen, wird eine neue Instanz dieser Klasse erzeugt und diese mithilfe der Methode RSS::addItem() dem RSS-Feed hinzugefügt. Die Einträge werden im RSS-Feed in der Reihenfolge abgelegt, in welcher Sie eingefügt werden - unabhängig vom Datum, da das Datum lediglich ein optionales Feld ist.
Der folgende Quellcode demonstriert das Erzeugen der Einträge.
<?php foreach ($rows as $row) { $item = new RSSitem(); // Titel $item->title = $row['BLOG_TITLE']; // Link $action = 'blog_read_read_blog'; $blog_id = $row['BLOG_ID']; $link = DisplayUtility::url("action=$action&blog_id=$blog_id", true); $link = str_replace(session_name() . '=' . session_id(), '', $link); $item->link = $link; // Text $item->description = $row['BLOG_TEXT']; // Datum $item->pubDate = date('r', $row['BLOG_CREATED']); // Eintrag hinzufügen $rss->addItem($item); } /* end foreach */ ?>
Beachten Sie den Code zum Erzeugen des Links. Dieser verweist auf die Aktion, welche zur Darstellung von Einträgen des Blogs verwendet wird. Die Aktion lautet "blog_read_read_blog". Wie bereits erwähnt, wurde dieser Name automatisch generiert. Die Funktion "url()" der Utility-Klasse "DisplayUtility" erzeugt, wie der Name sagt, eine URL inklusive der Adresse des Servers, Name und Pfad des Skripts und aller erforderlicher Parameter.
Der daraus entstehende Link enthält allerdings auch die aktuelle Session-Id. Diese ändert sich naturgemäß bei jedem Aufruf. Eigentlich sollte dies kein Problem darstellen, allerdings gibt es bedauerlicherweise eine Schwäche moderner RSS-Reader. Denn einige (nicht alle) von diesen sind so programmiert, dass Sie den Link eines RSS-Eintrags gleichzeitig als eindeutige Id verwenden. Sogar wenn explizit eine GUID vorhanden ist, wird diese in der Regel ignoriert und trotzdem der Link benutzt. Aus diesem Grund darf er sich nicht verändern, weil diese Programme andernfalls durcheinander geraten. Das ist der Grund, warum die Session-Id unbedingt aus dem Link entfernt werden muss und das ist auch der Grund, warum der Primärschlüssel des Eintrags im Link auftauchen muss. Dies ist keine Einschränkung des Frameworks, sondern eine unangenehme Eigenschaft der RSS-Reader. Leider werden Sie, wohl oder übel, vorerst mit diesem Problem leben müssen.
Weitere Details zur Verwendung dieser Klasse finden Sie in der API-Dokumentation der Klassen "RSS" und "RSSitem".
Zum Vergleich zeigt der folgende Auszug den gesamten Quellcode der Aktion im Zusammenhang:
<?php /* get entries from database */ $query = array( 'key' => 'blog.*', 'order_by' => 'blog_created', 'desc' => true, 'limit' => 10 ); $rows = $this->database->get($query); $rss = new RSS(); $rss->title = 'Blog'; $rss->description = 'the 10 most recent blog entries'; foreach ($rows as $row) { $item = new RSSitem(); // Titel $item->title = $row['BLOG_TITLE']; // Link $action = 'blog_read_read_blog'; $blog_id = $row['BLOG_ID']; $link = DisplayUtility::url("action=$action&blog_id=$blog_id", true); $link = str_replace(session_name() . '=' . session_id(), '', $link); $item->link = $link; // Text $item->description = $row['BLOG_TEXT']; // Datum $item->pubDate = date('r', $row['BLOG_CREATED']); // Eintrag hinzufügen $rss->addItem($item); } /* end foreach */ print utf8_encode($rss->toString()); exit(0); ?>
Wie Sie aus dem obigen Quellcode sehen konnten, wird in jedem Eintrag auf die Aktion "blog_read_read_blog" mit dem Parameter "blog_id" verwiesen. Bis jetzt besitzt diese Aktion allerdings diesen Parameter noch nicht. Der folgende Abschnitt wird demonstrieren, wie dieser Parameter dieser Aktion hinzugefügt wird.
Suchen Sie in dem Dokument die Aktion "blog_read_read_blog". Diese sollte momentan den folgenden Quellcode aufweisen:
<?php /** * blog_read_read_blog * * returns bool(true) on success and bool(false) on error * * Type: read * Permission: 0 * Templates: BLOG_READ_BLOG * * @access public * @return bool * @name plugin_blog::blog_read_read_blog() * @param array $ARGS array of params passed to the function */ function blog_read_read_blog ($ARGS) { /* check input data */ assert('is_array($ARGS);'); settype($ARGS, 'array'); /* global variables */ global $YANA; /* do something */ return true; } ?>
Zunächst sollten Sie prüfen, ob der Parameter "blog_id" überhaupt gesetzt ist, da dies nicht immer der Fall sein muss. Weil die Spalte "blog_id" in der Tabelle "blog" vom Typ "integer" ist, sollten Sie außerdem prüfen, ob der Eingabewert numerisch ist. Außerdem sollten Sie den Typ des Eingabewertes in einen Integerwert ändern. Der folgende Quellcode demonstriert dies.
<?php if (isset($ARGS['blog_id']) && is_numeric($ARGS['blog_id'])) { $id = (int) $ARGS['blog_id']; } ?>
An dieser Stelle kommt nun zum Tragen, dass Sie zuvor ( siehe oben ) im Template dieser Aktion für die Funktion "create" den Wert des Parameters "where" auf die Variable "$WHERE" gesetzt haben, denn dadurch können Sie nun durch Setzen der Variable "$WHERE" diesen Parameter beeinflussen.
Um den Wert einer Variable zu setzen rufen Sie die Funktion Yana::setVar auf. Setzen Sie den Wert der Variable auf "blog_id=$id".
<?php if (isset($ARGS['blog_id']) && is_numeric($ARGS['blog_id'])) { $id = (int) $ARGS['blog_id']; $YANA->setVar('WHERE', "blog_id=$id"); } ?>
Abschließend soll noch ein weiteres Feature demonstriert werden. Das Framework kann, falls ein RSS-Feed vorhanden ist, automatisch eine Grafik mit der Aufschrift "RSS" und einen Link auf den RSS-Feed der Anwendung einblenden. Um dieses Feature zu aktivieren, muss lediglich eine Variable gesetzt werden. Der Name dieser Variable lautet "RSS_ACTION" und ihr Wert sollte der Name der Aktion sein, welche den RSS-Feed erzeugt. In diesem Fall "blog_rss".
Die folgende Abbildung zeigt, wie dieses Symbol im Browser dargestellt wird.
Abbildung: Darstellung des Plugins mit RSS-Symbol (Firefox 2.0)
Zum Vergleich noch einmal der gesamte Quellcode der Aktion im Zusammenhang.
<?php /** * blog_read_read_blog * * returns bool(true) on success and bool(false) on error * * Type: read * Permission: 0 * Templates: BLOG_READ_BLOG * * @access public * @return bool * @name plugin_blog::blog_read_read_blog() * @param array $ARGS array of params passed to the function */ function blog_read_read_blog ($ARGS) { /* check input data */ assert('is_array($ARGS);'); settype($ARGS, 'array'); /* global variables */ global $YANA; $YANA->setVar('RSS_ACTION', 'blog_rss'); if (isset($ARGS['blog_id']) && is_numeric($ARGS['blog_id'])) { $id = (int) $ARGS['blog_id']; $YANA->setVar('WHERE', 'blog_id=' . $id); } return true; } ?>
Vergleichen Sie Ihr Ergebnis mit dem obigen Quellcode.
Mit diesem Schritt ist die Erstellung Ihres ersten Plugins erfolgreich abgeschlossen.
In diesem Tutorial haben Sie gelernt, wie Sie:
Damit ist dieses Tutorial beendet. Weitere Informationen und Codebeispiele finden Sie unter anderem im Kochbuch für Entwickler und der API-Dokumentation des Yana Frameworks.
Alle in diesem Tutorial verwendeten Quellcodes finden Sie auch in folgendem Paket: Blog-Plugin
Das folgende Tutorial wird erläutern, wie Sie Ihre Webanwendung mit dem Yana PHP-Framework und Server2Go auf eine CD/DVD-ROM brennen und direkt von dort starten können.
Der Zeitaufwand um alle Schritte nachzuvollziehen beläuft sich auf etwa 1/2 Stunde, nicht gerechnet die Zeit für eventuell notwendige Downloads. Literaturhinweise zu thematisch verwandten Artikeln finden Sie jeweils am Ende eines Abschnitts.
Bevor Sie mit diesem Tutorial beginnen, sollten Sie sicherstellen, dass Sie einige Vorbereitungen abgeschlossen haben, da Sie andernfalls an eine Stelle gelangen könnten, an der Sie das Tutorial nicht fortsetzen können.
Server2Go ist Donationware und darf auch für kommerzielle Anwendungen kostenlos verwendet werden. Die Software wird von Timo Haberkern entwickelt und betreut.
Grundlegende Kenntnisse im Aufbau und der Funktion von PHP und MySQL-Datenbanken werden in diesem Artikel vorausgesetzt.
Um ein PHP-Programm mit dem Yana PHP-Framework direkt von CD starten zu können gehen Sie bitte wie folgt vor.
Die Datei "library.php" ändern Sie wie folgt: define('YANA_CDROM',
true);
Falls Ihr Programm eine MySQL-Datenbank benötigt, gehen Sie wie folgt vor:
Nach der Installation Ihrer Datenbanken fahren Sie mit der Konfiguration fort.
Anschließend kann das Paket direkt auf CD-ROM gebrannt und sofort verwendet werden.
Im nächsten Kapitel werden Sie erfahren, wie Sie Server2Go und das Yana PHP-Framework zusammen mit der Portable-Edition des Firefox Browser verwenden können.
Sie haben die Möglichkeit mit Server2Go auch einen Firefox-Browser direkt von CD zu starten. Die folgende Anleitung erklärt Ihnen, was dazu nötig ist.
Achtung: Es gibt ein ZIP-Archiv mit allen erforderlichen Konfigurationsdateien, welches Sie verwenden können. Entpacken Sie das Archiv und überschreiben Sie alle Originaldateien. Danach sind Sie bereits fertig und können Ihre Anwendung direkt auf CD-ROM brennen.
Falls Sie das Archiv nicht verwenden und die Schritte stattdessen von Hand durchführen wollen, fahren Sie mit der Konfiguration wie folgt fort.
[FirefoxPortable]
FirefoxDirectory=App\firefox
ProfileDirectory=Data\profile
PluginsDirectory=Data\plugins
SettingsDirectory=Data\settings
FirefoxExecutable=firefox.exe
AdditionalParameters=-contentLocale de-DE -UILocale de-DE
LocalHomepage=
DisableSplashScreen=true
DisableIntelligentStart=false
AllowMultipleInstances=true
SkipChromeFix=false
SkipCompregFix=false
WaitForFirefox=true
RunLocally=true
Eine Anleitung zu den verwendeten Optionen finden Sie in der Datei
"FirefoxPortable/Other/FirefoxPortableSource/Readme.txt". Diese Datei
wird mit Firefox Portable ausgeliefert. Die Option
"AdditionalParameters" sorgt hier für das Starten der deutschen
Version. Anschließend kann das Paket auf CD-ROM gebrannt werden.
Dieser Abschnitt beschreibt den Status des Dokumentes zum Zeitpunkt der Veröffentlichung. Spätere Dokumente können den vorliegenden Stand ersetzen. Die jeweils aktuelle Version finden Sie online auf der Projekt-Webseite des Yana Frameworks.
Dieses Dokument ist noch keine endgültige Fassung (Final Release) und seine Inhalte können sich ändern. Kommentierungen der gegenwärtigen Version dieser Arbeit sind erwünscht.
Die aktuelle Version dieses Dokumentes wird innerhalb des Subversion-Repository gepflegt. Eine Liste von Änderungen kann aus dem Repository jederzeit exportiert werden.
Version | State | Date |
---|---|---|
nicht versioniert | Working Draft | 2009-07-01 - 2009-08-31 |
0.5 | Call for Comments | 2009-09-17 - 2009-10-05 |
0.5.1 | Working Draft | 2009-10-06 - 2010-09-13 |
0.6 | Working Draft | 2010-09-14 - heute |
0.7 | Call for Comments | nachfolgend |
Dieser Abschnitt definiert in diesem Dokument verwendete, feststehende Bezeichnungen.
ELEMENT database (description?, (include | table | view | form | function | sequence | initialization)*, changelog?) ATTRIBUTE name string title string charset string datasource string readonly bool
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | - | - | Ein eindeutiger Name welcher diese Datenbank identifiziert. Default ist der Dateiname. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
title | string | - | - | Title ist eine Beschriftung, welche in der Nutzeroberfläche angezeigt werden sollte wenn das Objekt anzeigt wird. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
charset | string | - | - | Der bevorzugte Zeichensatz welcher verwendet wird wenn Datenbankobjekte erstellt werden und/oder mit der Datenbank kommuniziert wird. Der Zeichensatz kann nur zum Zeitpunkt der Erstellung der Datenbank gesetzt werden. Wenn Sie sich dafür entscheiden, eine vorhandene Datenbank zu verwenden, beachten Sie bitte, dass der tatsächlich verwendete Zeichensatz ein anderer sein könnte. |
datasource | string | - | - | Die Interpretation des Attributs datasource (Datenquelle) hängt von der Implementierung ab. Für das Yana Framework ist es eine benannte Datenquelle. Sie können benannte Datenbankverbindungen über das Administrationsmenü setzen. |
readonly | bool | - | no | Sie können die Datenbank auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Tun Sie dies wenn Sie ein Datenbakviewer erstellen möchten, oder eine Anwendung auf CD-ROM. |
Ein Wurzelknoten, welcher die wichtigsten Eigenschaften und/oder Anforderungen spezifiziert. Diese können verwendet werden, wenn die Datenbank über ein Skript erstellt wird, oder ein Datenbankclient eine Verbindung herstellt.
Der Zeichensatz (charset) soll während des Anlegens der Datenbank gesetzt werden. Typische Zeichensätze sind: utf-8, ascii, iso-8859-1. Beachten Sie, dass einige DBMS verschiedene Schreibweisen desselben Zeichensatzes haben, oder Zeichensätze unterstützen, die andere DBMS nicht anbieten. Die Implementierung muss eine Liste von gültigen Zeichensätzen zur Verfügung stellen und automatisch auf die korrekte Schreibweise für das Ziel-DBMS abbilden. Die Implementierung kann einen Fehler melden, wenn ein nicht unterstützter Zeichensatz verwendet wird.
Die Datenquelle (datasource) ist im Allgemeinen ein Bezeichner für einen bestimmten Satz von Verbindungsparametern zu einer spezifischen Datenbank. Das kann eine JNDI Data-Source für Java, eine ODBC Data-Source für C#, oder eine andere benannte Datenquelle für eine andere Sprache sein.
Wenn eine Oberfläche für eine Datenbank dargestellt wird, kann die Implementierung das Attribut title der Datenbank als Überschrift wählen.
ELEMENT description (#PCDATA)
Die Beschreibung dient zwei Zwecken: 1. der Offline-Dokumentation 2. der Online-Dokumentation.
Eine Beschreibung ist stets optional. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird.
Der Formulargenerator kann die Beschreibung verwenden, um auf einer generierten Oberfläche kontextsensitive Hilfe, oder Zusatzinformation zur Verfügung zu stellen (abhängig von der Implementierung).
ELEMENT include (#PCDATA)
Datenbankdefinitionen können in mehrere Dateien geteilt und rekursiv eingebunden werden. Zum Beispiel kann das notwendig sein, wenn Sie eine Referenz auf eine Tabelle erstellen möchten, welche an einer anderen Stelle definiert worden ist.
Die Liste der eingebundenen Dateien (Inlcudes) kann entweder Dateinamen, oder Bezeichner enthalten, welche durch die Anwendung zu Dateinamen umgewandelt werden können.
Beachten Sie, dass Sie nur Datenbankdefinitionen einbinden sollten, welche dieselbe Datenquelle (datasource) verwenden.
Die Kindknoten der Database-Tags der eingebundenen Dateien sollten in der Reihenfolge ihres Auftretens zum Datenbankknoten der Quelldatei hinzugefügt werden. Die Database-Elemente selbst sollen ignoriert werden. Wenn die eingebundene Datei weitere Dateien einbindet, dann sollten diese rekursiv behandelt werden. Sollte eine Datei mehrfach gelistet sein, so muss sie genau 1 Mal eingebunden werden. Falls eine Datei rekursiv eine weitere einbindet, welche jedoch bereits geladen wurde, so muss diese übersprungen und darf nicht zum zweiten Mal geladen werden. Eingebettete Dateien dürfen keine bereits vorhandenen Objekte redefinieren. z.B. darf eine eingeschlossene Datei nicht eine Tabellendefinition der Quelldatei überschreiben. Wenn ein bereits vorhandenes Element gefunden wird, muss ein Fehler gemeldet werden.
ELEMENT sequence (description?) ATTRIBUTE name string start integer increment string min integer max integer cycle bool
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Zahlenfolge identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
start | integer | - | - | Eine Zahlenfolge (Sequence) fängt immer mit einem Startwert an. Default ist der Minimalwert für aufsteigende, bzw. der Maximalwert für absteigende Zahlenfolgen. Hinweis: der Startwert muss im Bereich der minimalen und maximalen Zahl liegen. |
increment | string | - | 1 | Ein Inkrement (oder Schrittweite) spezifiziert die Zahl, welche zur Zahlenfolge addiert wird, zur Berechnung des Nachfolgers ihres aktuellen Wertes. |
min | integer | - | - | Der Minimalwert ist eine Untergrenze für die Werte einer Zahlenfolge. Alle Werte müssen größer oder gleich dem Minimalwert sein. Der Minimalwert kann nicht größer als der Maximalwert sein. Default ist 1 für aufsteigende und PHP_INT_MIN für absteigende Zahlenfolgen. |
max | integer | - | - | Der Maximalwert ist eine Obergrenze für die Werte einer Zahlenfolge. Alle Werte müssen kleiner oder gleich dem Maximalwert sein. Der Maximalwert kann nicht kleiner als der Minimalwert sein. Default ist PHP_INT_MAX für aufsteigende und -1 für absteigende Zahlenfolgen. |
cycle | bool | - | no | Wenn eine Zahlenfolge ein Nummernkreis (cycle) ist und der Wert der Zahlenfolge eine Ober- oder Untergrenze erreicht, so wird diese zurückgesetzt auf den Minimalwert für eine aufsteigende, bzw. den Maximalwert für eine absteigende Zahlenfolge. |
Zahlenfolgen (Sequence) sind ganze Zahlen (Integer), in Verbindung mit einer Funktion zur Berechnung des Nachfolgers. Sie erfüllen verschiedene Aufgaben. Gewöhnlich werden sie verwendet, um eindeutige Id's automatisch zu generieren.
Beachten Sie, dass es implizite und explizite Zahlenfolgen gibt. Z.Bsp. wird implizit eine Zahlenfolge erzeugt, wenn eine Tabellenspalte mit der Eigenschaft Autoincrement angelegt wird. Implizite Zahlenfolgen dürfen nicht manuell definiert werden, da diese durch das DBMS selbst angelegt und verwaltet werden.
Beachten Sie auch, dass einige DBMS die Zahl 0 und den Wert NULL als gleich behandeln. Daher sollten Sie darauf achten, KEINE Zahlenfolge zu erzeugen, welche zu irgendeinem Zeitpunkt den Wert 0 annehmen kann. Außerdem können einige Anwendungen den Index 0 für Standardwerte reservieren (z.Bsp. ein Data-Warehouse).
Obwohl Zahlenfolgen Teil des SQL-2003 Standards sind, werden sie von den meisten Herstellern nicht unterstützt. Mit Ausnahme von PostgreSQL, wo diese ein bekanntes Feature darstellen. Sie können jedoch für andere DBMS simuliert werden.
ELEMENT initialization (#PCDATA) ATTRIBUTE dbms string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
dbms | string | - | generic | Der Name des Ziel-DBMS. Der Wert "generic" bedeutet, dass die Definition für jedes DBMS zutreffend ist. Gewöhnlich wird das als Rückfalloption für DBMS verwendet, an welche Sie entweder beim Erstellen der Datenbankstruktur noch nicht gedacht haben, oder welche das fragliche Feature nicht unterstützen. |
SQL-Anweisungen zum Initialisieren der Datenbank, welche ausgeführt werden sollen, direkt nachdem die Datenbankstruktur publiziert wurde. Die Syntax kann entweder allgemein gültig (generic) sein oder DBMS-spezifisch.
Die folgenden Werte werden für das DBMS-Attribut vorgeschlagen: 'generic', 'db2', 'dbase', 'frontbase', 'informix', 'interbase', 'msaccess', mssql,'' mysql,'' oracle,'' postgresql,'' sybase,'' sqlite'.
ELEMENT table (description?, (grant* | primarykey | foreign* | trigger* | constraint* | declaration | index)*) ATTRIBUTE name string title string readonly bool inherits string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name, welcher die Tabelle identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
title | string | - | - | Title ist eine Beschriftung, welche in der Nutzeroberfläche angezeigt werden sollte wenn das Objekt anzeigt wird. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
readonly | bool | - | no | Sie können die Tabelle auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. |
inherits | string | - | - | Name der Elterntabelle. |
Ein Tabelle ist eine Reihe von Spaltendefinitionen und Eigenschaften, welche alle Spalten der Tabelle gemeinsam haben, z. Bsp.: Trigger und Indexes.
Vererbung hat für Tabellen folgende Bedeutung: eine Kindtabelle AB erweitert die Struktur und Daten einer Elterntabelle A um die Elemente B. Alle Zeilen in AB besitzen sämtliche Spalten definiert in A + sämtliche Spalten aus B. B bleibt dabei unverändert. Wenn sich die Struktur von A ändert, ändert sich die Struktur von AB ebenso. Jedes Element von AB kann auch als ein Element von A interpretiert werden, aber nicht umgekehrt.
Technisch gesprochen: der Primärschlüssel der Kindtabelle ist ein Fremdschlüssel, der auf den Primärschlüssel der Elterntabelle verweist.
Dies ist ein Unterschied zu PostgreSQL, welches multiple Vererbung mit n Elterntabellen unterstützt - verbunden mit allen Konsequenzen und Problemen, welche dieses Verhalten verursacht.
ELEMENT grant EMPTY ATTRIBUTE role string user string level integer select bool insert bool update bool delete bool grant bool
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
role | string | - | - | Die Rolle die ein Benutzer innerhalb einer Benutzergruppe spielt. |
user | string | - | - | Die Gruppe zu der ein Benutzer gehört. |
level | integer | - | - | Das Sicherheitslevel ist eine ganze Zahl zwischen 0 und 100. Dies kann als ein Wert von 0-100 Prozent verstanden werden, wobei 0 dem niedrigsten und 100 dem höchsten Zugang entspricht. |
select | bool | - | yes | Gibt Auskunft ob der Nutzer Select-Abfragen auf dem Datenbankobjekt ausführen darf. |
insert | bool | - | yes | Gibt Auskunft ob der Nutzer Insert-Anweisungen auf dem Datenbankobjekt ausführen darf. |
update | bool | - | yes | Gibt Auskunft ob der Nutzer Update-Anweisungen auf dem Datenbankobjekt ausführen darf |
delete | bool | - | yes | Gibt Auskunft ob der Nutzer Delete-Anweisungen auf dem Datenbankobjekt ausführen darf |
grant | bool | - | yes | Gibt Auskunft ob der Nutzer seine Sicherheitsprivilegien vorübergehend anderen Nutzern gewähren darf. |
Die Rechteverwaltung bietet 3 Schichten, wovon in diesem Dokument alle optional sind. Eine Implementierung muss jedoch mindestens eine oder mehrere dieser Möglichkeiten umsetzen.
In Analogie zu Datenbanken gibt es auch eine "grant"-Option, welche es Nutzern gestattet, Sicherheitsprivilegien, welche sie besitzen, vorübergehend anderen Nutzern zu gewähren. Folglich kann ein Manager alle seine Rechte auf einen Assistenten übertragen (und dies später widerrufen), während er im Urlaub ist.
Sie können festlegen, dass jeder Manager des Bereichs Human Resources mit einem Sicherheitslevel von 50 oder höher, einen neuen Mitarbeiter anlegen und Lohndaten einsehen kann, aber mindestens ein Manager der Gruppe Human Resources mit einem Sicherheitslevel von 80 erforderlich ist, um diese Daten nachträglich zu verändern.
Sie können auch einige der Angaben auslassen, um vielleicht jedem Nutzer mit einem Sicherheitslevel von 1 das Anzeigen eines Katalogformulars zu gestatten, oder allen Mitgliedern der Verkaufsabteilung Zugriff auf Verkaufsdaten zu erlauben.
Sie können genau festlegen, was ein Nutzer tun darf oder auch nicht: select (anzeigen), insert (erstellen), update (editieren), delete (löschen).
Beachten Sie, dass mehrere Grant-Elemente angegeben werden können, um mehrere Alternativen zu definieren. Z.Bsp. können Nutzer entweder ein Mitglied der Gruppe Sales, oder in der Rolle eines Geschäftsleiters sein, um Verkaufsinformationen abrufen und editieren zu können.
Wenn kein Grant-Element vorhanden ist, soll das Element öffentlich sein. Dies bedeutet, dass keine Sicherheitsüberprüfung durchgeführt wird. Wenn mindestens 1 Grant-Element existiert, darf keinem Benutzer erlaubt sein eine Operation auszuführen, sofern kein Grant existiert welcher ihm dies ausdrücklich erlaubt.
Das Yana Framework implementiert zusätzlich zu den genannten Einstellungen ein System von Anwendungsprofilen. Anwendungsprofile können verschiedene Tochtergesellschaften innerhalb Ihrer Firma definieren. Z.Bsp. Europa oder Asien. Falls Implementierungen, die Verwaltung mehrerer unabhängiger Mandanten auf einer gemeinsamen Installation unterstützen sollen, wird empfohlen ein vergleichbares System zu übernehmen.
ELEMENT primarykey (#PCDATA)
Der Primärschlüssel ist der Name einer einzelnen Spalte innerhalb der Tabelle, die eindeutige Werte besitzt und verwendet wird, um jede Zeile innerhalb der Tabelle zu identifizieren.
Die Software muss überprüfen, ob die angegebene Spalte existiert. Andernfalls muss ein Fehler gemeldet werden.
Jede Tabelle muss genau 1 Primärschlüssel besitzen. Zusammengesetzte Primärschlüssel (Compound Primary Keys) werden nicht unterstützt.
ELEMENT declaration (array | bool | color | date | enum | file | float | html |image | inet | integer | list | mail | password | range | reference | set | string | text | time | timestamp |url)*
Das Declaration-Element ist ein einfacher Container, der mehrere Spaltendefinitionen enthalten kann.
ELEMENT trigger (#PCDATA) ATTRIBUTE name string dbms string on string insert bool update bool delete bool
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | - | - | Ein eindeutiger Name welcher diesen Trigger identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
dbms | string | - | generic | Der Name des Ziel-DBMS. Der Wert "generic" bedeutet, dass die Definition für jedes DBMS zutreffend ist. Gewöhnlich wird das als Rückfalloption für DBMS verwendet, an welche Sie entweder beim Erstellen der Datenbankstruktur noch nicht gedacht haben, oder welche das fragliche Feature nicht unterstützen. |
on | string | - | before |
|
insert | bool | - | no | auslösen bei Insert-Anweisungen |
update | bool | - | no | auslösen bei Update-Anweisungen |
delete | bool | - | no | auslösen bei Delete-Anweisungen |
Trigger sind ein Feature von Datenbanksystemen, welches es erlaubt, auf bestimmte Datenbankereignisse mit der Ausführung von Code zu reagieren. Trigger werden durch Insert-, Update- oder Delete-Anweisungen, oder eine Kombination dieser, ausgelöst. Sie werden entweder vor (before), nachdem (after) oder anstatt (instead) der Anweisung ausgeführt. Nach dem Auslösen eines Triggers, wird der angegebene Code durch die Datenbank ausgeführt.
Die Syntax der Implementierung des Triggers hängt jedoch stark vom gewählten DBMS ab. Nicht alle DBMS unterstützen alle Features. Zum Beispiel: unterstützen nicht alle DBMS Trigger, die anstatt (instead) einer Anweisung ausgeführt werden und diese ersetzen.
Beachten Sie, dass ein Trigger eine benutzerdefinierte Funktion impliziert. Einige DBMS verlangen daher, dass diese Funktion explizit erzeugt und für den Trigger nur der Name der Funktion angeben wird. Andere DBMS erlauben, dass Sie den Funktionscode zusammen mit dem Trigger angeben.
Wenn ein Trigger eine Funktionalität verwendet, die durch das gewählte DBMS nicht unterstützt wird, wird dieses beim Versuch den Trigger zu erstellen einen Fehler melden. Die Implementierung selbst braucht dies nicht zu prüfen.
Trigger, welche die DBMS-Einstellung "generic" verwenden, müssen emuliert werden. In diesem Fall muss der Code durch die XDDL-kompatible Software, anstatt durch die Datenbank, ausgeführt werden. Die Implementierung kann die erforderliche Syntax für den Code selbst festlegen. Für diesen Fall wird empfohlen, dass das Attribut Code für derartige Trigger beschränkt wird auf gültige Callbacks (Funktions- oder Methodennamen). Das Yana Framework verlangt, dass das Attribut Code für emulierte Trigger ein gültiger Name einer nutzerdefinierten PHP-Funktion sein muss. Nähere Informationen zu diesem Thema finden Sie auch im Handbuch zur Datenbank-Schnittstelle.
ELEMENT constraint (#PCDATA) ATTRIBUTE name string dbms string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | - | - | Ein eindeutiger Name welcher diesen Constraint identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
dbms | string | - | generic | Der Name des Ziel-DBMS. Der Wert "generic" bedeutet, dass die Definition für jedes DBMS zutreffend ist. Gewöhnlich wird das als Rückfalloption für DBMS verwendet, an welche Sie entweder beim Erstellen der Datenbankstruktur noch nicht gedacht haben, oder welche das fragliche Feature nicht unterstützen. |
Ein Constraint ist ein boolescher Ausdruck, der jederzeit erfüllt sein muss, damit die Tabellenzeile gültig ist. Die Datenbank sollte dies sicherstellen. Für Datenbanken, welche dieses Feature nicht haben, kann der DBMS-Typ "generic" gesetzt werden, um dieses zu simulieren.
Wenn ein Constraint den DMBS-Typ "generic" verwendet und die XDDL-Implementierung nicht sicherstellen kann, dass die Datenbank das Feature unterstützt, dann muss diese den Constraint anstelle der Datenbank validieren. Die Implementierung kann die erforderliche Syntax für den Code selbst festlegen. Bei der Simulation dürfen Constraints auf Spalten äquivalent zu Constraints auf Tabellen behandelt werden. Das Yana Framework verwendet PHP als Sprache zur Definition generischer Constraints. Es liefert dazu ein assoziatives Array $ROW, welches Kopien der Werte der aktuellen Zeile beinhaltet. Die Schlüssel dieses Arrays entsprechen den Spaltennamen in Kleinbuchstaben.
ELEMENT bool (description?, grant*, constraint*, default*) ATTRIBUTE name string notnull bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | yes | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | no | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Spalten vom Typ Boolean dürfen zwei Werte annehmen: True und False.
Boolesche Werte werden nicht von allen DBMS unterstützt , jedoch können diese durch die Verwendung von Integer-Spalten leicht simuliert werden.
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.
HTML:
<input type="checkbox" value="true" name="{name}"/>
undefined <input type="radio" value="*" name="{name}"/> null <input type="radio" value="true" name="{name}"/> false <input type="radio" value="false" name="{name}"/>
<select name="{name}"> <option value="*">null</option> <option value="true">true</option> <option value="false">false</option> </select>
ELEMENT default (#PCDATA) ATTRIBUTE dbms string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
dbms | string | - | generic | Der Name des Ziel-DBMS. Der Wert "generic" bedeutet, dass die Definition für jedes DBMS zutreffend ist. |
Bei neu erstellten Datensätzen werden Spalten, für welche kein anderer Wert angegeben wurde, automatisch auf den Default-Wert gesetzt.
Der Typ des Werts hängt vom Typ der Spalte ab. Der physische Default-Wert hängt zusätzlich auch vom DBMS ab.
Ein gutes Beispiel ist der Datentyp Boolean, der durch PostgreSQL unterstützt wird und dessen physischer Default-Wert daher True oder False ist. Für MySQL wird diese Spalte jedoch als TinyInt gespeichert, mit den Default-Werden 1 oder 0.
Jedoch sind die DBMS-unabhängigen (generic) Default-Werte True oder False. Die Implementierung muss diese Werte automatisch umwandeln.
ELEMENT color (description?, grant*, constraint*, default*) ATTRIBUTE name string notnull bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | no | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Spalten vom Typ Color enthalten einen Farbwert in Hexadezimalschreibweise mit führendem '#'-Zeichen. Beispiel: #F0F0F0.
Diese Spalten können als Texte mit einer Länge 7 Zeichen umgesetzt werden.
Die Darstellung sollte als Input-Steuerelement erfolgen. Zusätzlich kann eine Eingabehilfe für Nutzer implementiert werden.
HTML5:
<input type="color" {required="notnull"} value="{default}" name="{name}"/>
ELEMENT integer (description?, grant*, constraint*, default*) ATTRIBUTE name string autoincrement bool unsigned bool fixed bool length integer notnull bool unique bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
autoincrement | bool | - | no | Autoincrement ist ein MySQL-Feature, welches jedoch für andere DBMS emuliert werden kann. Es kann jedoch nur auf Spalten vom Typ Integer angewendet werden. Sie sollten beachten, dass die Benutzereingabe Vorrang vor dem AutoIncrement hat, welches lediglich einen Default-Wert darstellt. |
unsigned | bool | - | no | Eine Zahl ohne Vorzeichen muss stets ein positiver Wert sein. Das bedeutet, jeder Wert kleiner als 0 ist ungültig. Eine Implementierung muss einen Fehler melden, wenn für eine vorzeichenlose Spalte ein negativer Wert gegeben wird. (Beachten Sie, dass MySQL automatisch und ohne Warnung einen negativen Wert durch 0 ersetzt.) |
fixed | bool | - | no | Setzt die Eigenschaft "zerofill" für MySQL. Für Zahlen fester Länge muss der Wert stets auf die definierte volle Anzahl an Ziffern erweitert werden, indem führende Nullen ergänzt werden. Falls das Attribut length nicht gesetzt ist, muss das Attribut fixed ignoriert werden. |
length | integer | - | - | Die maximale Zahl an Ziffern. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | no | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Spalten vom Typ Integer können jede ganze Zahl enthalten, die durch die Datenbank und Programmiersprache angezeigt werden kann.
Die oberen und unteren Grenzen für Zahlenwerte hängen vom Typ des Systems ab. Im Allgemeinen: liegen auf 32-Bit-System die darstellbaren Zahlen im Bereich [-2^31, 2^31]. Für 64-Bit-Systeme können die Zahlen größer sein[-2^63, 2^63]. Allerdings nur, wenn sämtliche verwendete Software 64-Bit integer-Werte unterstützt.
Beachten Sie! 64-bit-und 32-Bit- Anwendungen müssen nicht kompatibel sein. Besonders, wenn Sie einen 64-Bit-Datenbankserver mit einer 32-Bit-Anwendung oder umgekehrt verwenden. Seien Sie gewarnt, dass ein Zahlenüberlauf oder -unterlauf auftreten kann, wenn eine große 64-Bit in eine kleine 32-Bit Zahl umgewandelt wird. Beachten Sie, dass das für Datums- und Zeitangaben ebenso gilt!
Einzeilige Texte und Zahlen werden beim Editieren der Spalte als Inputfeld dargestellt. Ist die Spalte nicht editierbar, wird der Inhalt als Textzeile dargestellt.
HTML5:
<input type="number" step="1" {required="notnull"} name="{name}"/>
ELEMENT float (description?, grant*, constraint*, default*) ATTRIBUTE name string unsigned bool length integer precision integer notnull bool unique bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
unsigned | bool | - | no | Eine Zahl ohne Vorzeichen muss stets ein positiver Wert sein. Das bedeutet, jeder Wert kleiner als 0 ist ungültig. Eine Implementierung muss einen Fehler melden, wenn für eine vorzeichenlose Spalte ein negativer Wert gegeben wird. (Beachten Sie, dass MySQL automatisch und ohne Warnung einen negativen Wert durch 0 ersetzt.) |
length | integer | - | - | Die maximale Zahl an Ziffern. |
precision | integer | - | - | Definiert die Länge der Nachkommastellen. Wenn vorhanden, muss das Attribut length ebenfalls gesetzt sein. Die maximale vollen Stellen ist: length - precision. Beachten Sie, dass der Wert precision nicht größer sein darf als das Attribut length. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | no | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Spalten vom Typ Float können jede Zahl enthalten, die durch die Datenbank und Programmiersprache angezeigt werden kann. Dabei kann es sich entweder um ganze Zahlen, Fließkommazahlen, oder Festpunktzahlen (mit fester Anzahl Nachkommastellen) handeln.
Die oberen und unteren Grenzen für Werte hängen vom Typ des Systems ab. Beachten Sie, dass für Fließkommazahlen die "maximale Länge" die maximale Anzahl an Ziffern, inklusive der gebrochenen Stellen, meint. Daher werden Sie für sehr große oder sehr kleine Zahlen Genauigkeit verlieren. Für Festkommazahlen werden Maximum und Minimum um die Anzahl der für die Darstellung der Nachkommastellen reservierten Dezimalstellen reduziert.
Beachten Sie! 64-bit-und 32-Bit- Anwendungen müssen nicht kompatibel sein. Besonders, wenn Sie einen 64-Bit-Datenbankserver mit einer 32-Bit-Anwendung oder umgekehrt verwenden. Seien Sie gewarnt, dass ein Zahlenüberlauf oder -unterlauf auftreten kann, wenn eine große 64-Bit in eine kleine 32-Bit Zahl umgewandelt wird. Beachten Sie, dass das für Datums- und Zeitangaben ebenso gilt!
Einzeilige Texte und Zahlen werden beim Editieren der Spalte als Inputfeld dargestellt. Ist die Spalte nicht editierbar, wird der Inhalt als Textzeile dargestellt.
HTML5:
<input type="number" {required="notnull"} name="{name}"/>
ELEMENT range (description?, grant*, constraint*, default*) ATTRIBUTE name string notnull bool unique bool readonly bool min float max float step float title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
min | float | ja | - | Kleinster erlaubter Wert. |
max | float | ja | - | Größter erlaubter Wert. |
step | float | - | 1.0 | Minimale Schrittweite. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Spalten vom Typ Range können jede Zahl enthalten, die durch die Datenbank und Programmiersprache angezeigt werden kann. Dabei kann es sich entweder um ganze Zahlen, Fließkommazahlen, oder Festpunktzahlen (mit fester Anzahl Nachkommastellen) handeln.
Dieser Typ muss analog zu Spalten vom Typ Float behandelt werden. Die Angabe der Attribute "min" und "max" impliziert einen oder mehrere Constraints. Der Wert der Spalte darf nicht kleiner als "min" und nicht größer als "max" sein. Das Attribut "max" darf nicht kleiner als "min" sein. Die Spalte muss mindestens 2 gültige Werte erlauben. Das heißt: "min" + "step" muss kleiner oder gleich "max" sein. Der Wert "max" - "min" sollte ein Vielfaches von "step" betragen. Der Wert "step" darf nicht negativ sein.
Dargestellt werden Zahlen dieses Typs als horizontaler Schieberegler ("imprecise number-input control"). Die Wahl der genauen Umsetzung darf dem Client vorbehalten werden.
HTML5:
<input type="range" {required="notnull"} min="{min}" max="{max}" step="{step}" name="{name}"/>
ELEMENT string (description?, grant*, constraint*, default*) ATTRIBUTE name string length integer notnull bool unique bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
length | integer | - | - | Die maximale Zahl an Zeichen. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Spalten vom Typ String können eine einzelne Linie Text enthalten.
Beachten Sie, dass String-Werte keine Zeilenumbrüche enthalten dürfen. Dabei handelt es sich um die Zeichen \f, \r und \n. Aus Sicherheitsgründen dürfen Werte das Zeichen \#0 nicht enthalten.
Einzeilige Texte und Zahlen werden beim Editieren der Spalte als Inputfeld dargestellt. Ist die Spalte nicht editierbar, wird der Inhalt als Textzeile dargestellt.
HTML5:
<input type="text" maxlength="{length}" {required="notnull"} name="{name}"/>
ELEMENT mail (description?, grant*, constraint*, default*) ATTRIBUTE name string length integer notnull bool unique bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
length | integer | - | - | Die maximale Zahl an Zeichen. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Spalten vom Typ Mail können jede gültige E.-Mailadresse enthalten.
Mails werden als Werte vom Typ String implementiert. Die Syntax von E.-Mailadressen wird in RFC 822 spezifiziert. Für PHP-Implementierungen wird zur Validierung von E.-Mailadressen folgender Code empfohlen: filter_var($email, FILTER_VALIDATE_EMAIL) === true. Andere Implementierungen können den folgenden regulären Ausdruck verwenden: [\w\d-_\.]{1,}\@[\w\d-_\.]{2,}\.[\w\d-_\.]{2,}.
Beim Editieren wird die Spalte als Inputfeld dargestellt. Dies ist identisch zur Darstellung eines Strings.
Eingaben vom Datentyp "mail" sollten bei der Darstellung im Browser automatisch verschlüsselt werden, um Datendiebstahl zu erschweren. Dies gilt grundsätzlich für alle angezeigten E.-Mailadressen. Die Umsetzung erfolgt im Yana Framework automatisch in der Darstellungsschicht. Eingriffe von Hand sich nicht erforderlich.
HTML5:
<input type="email" maxlength="{length}" {required="notnull"} name="{name}"/>
ELEMENT url (description?, grant*, constraint*, default*) ATTRIBUTE name string length integer notnull bool unique bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
length | integer | - | - | Die maximale Zahl an Zeichen. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Spalten vom Typ URL entsprechen dem Typ "String", mit dem Unterschied, dass geprüft wird ob die Eingabe eine syntaktisch korrekte URL ist.
URLs werde als Werte vom Typ String implementiert. Die Syntax von URIs ist in RFC 3986 spezifiziert. Für PHP-Implementierungen wird zur Validierung folgender Code empfohlen: filter_var($url, FILTER_VALIDATE_URL) === true.
Einzeilige Texte und Zahlen werden beim Editieren der Spalte als Inputfeld dargestellt. Ist die Spalte nicht editierbar, wird der Inhalt als Textzeile dargestellt.
HTML5:
<input type="url" {required="notnull"} name="{name}"/>
ELEMENT password (description?, grant*, constraint*, default*) ATTRIBUTE name string notnull bool unique bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Eine Spalte vom Typ Password wird verwendet, um verschlüsselte Passwörter zu verwalten.
Passwörter sind Hashwerte. Die Werte müssen aus der Nutzereingabe mit einem Hash-Algorithmus, wie MD5, berechnet werden. Passwörter dürfen nicht als Klartext gespeichert sein.
Passwörter werden nicht als Text angezeigt, sondern als Input-Element vom Typ "password".
HTML5:
<input type="password" {required="notnull"} name="{name}"/>
ELEMENT inet (description?, grant*, constraint*, default*) ATTRIBUTE name string notnull bool unique bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Spalten vom Typ Inet bieten die Möglichkeit, automatisch die IP-Adresse des Nutzers zu speichern.
Spalten vom Typ Inet werden als Werte vom Typ String implementiert. Die Implementierung muss IPv4 und IPv6 unterstützen. Die Syntax von IPv6 wird in RFC 2460 spezifiziert.
Für PHP-Implementierungen wird zur Validierung folgender Code empfohlen: filter_var($inet, FILTER_VALIDATE_IP) === true. Andere Implementierungen können die folgenden regulären Ausdrücke verwenden:
In der Regel werden Spalten dieses Typs nicht als editierbar markiert. Falls doch, wird ein Inputfeld angezeigt.
HTML5:
<input type="text" {required="notnull"} name="{name}"/>
ELEMENT text (description?, grant*, constraint*) ATTRIBUTE name string length integer notnull bool unique bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
length | integer | - | - | Die maximale Zahl an Zeichen. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Spalten vom Typ Text können mehrere Textzeilen enthalten. Ihre Länge ist nicht begrenzt.
Beachten Sie, dass die Länge aus technischen Gründen beschränkt sein kann. Der physische Datentyp hängt vom gewählten DBMS ab. Darüber hinaus kann das DBMS das Erstellen eines Index auf einer Textspalte verweigern, oder einen Volltextindex mit spezifischen Eigenschaften erstellen.
Aus Sicherheitsgründen dürfen Werte das Zeichen \#0 nicht enthalten.
Alle für HTML reservierten Zeichen müssen maskiert werden. Zusätzlich kann die Implementierung Ein- und Ausgabefilter definieren. Diese können zum Beispiel verwendet werden, um Smilies umzuwandeln und/oder Spam und Floods zu unterbinden.
Zum Beispiel implementiert, das Yana Framework mehrere Filter, um offensichtlichen Vandalismus zu verhindern.
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").
HTML5:
<textarea maxlength="{length}" {required="notnull"} name="{name}"/>
ELEMENT html (description?, grant*, constraint*) ATTRIBUTE name string length integer notnull bool unique bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
length | integer | - | - | Die maximale Zahl an Zeichen. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Spalten vom Typ HTML können mehrere Zeilen Hypertext im XHTML-Format enthalten.
Sie sollten bedenken, dass Hypertext Tags und Entitäten enthalten kann. Die Bestimmung der wahren Länge eines solchen Textes kann heikel sein.
Es dürfen keine Dateien (wie zum Beispiel Grafiken) an den HTML-Inhalt angehängt oder eingebettet werden. Jedoch darf die Spalte einen Tag enthalten, welcher auf eine Datei verweist, welche an anderer Stelle gespeichert ist.
Aus Sicherheitsgründen dürfen Werte das Zeichen \#0 nicht enthalten.
Zusätzlich kann die Implementierung Ein- und Ausgabefilter definieren. Zum Beispiel um XSS-Angriffe und Vandalismus zu verhindern.
Um HTML-Spalten zu editieren, kann die Implementierung einen eingebetteten HTML-Editor verwenden. Eigenschaften und Verhalten dieses Editors sind nicht spezifiziert. Für die Ausgabe müssen HTML-Spalten als interpretierter Hypertext, gemäß den Anforderungen des XHTML 1.0 Standards, oder eines Nachfolgers dieses Standards (z.Bsp. HTML 5), dargestellt werden.
ELEMENT date (description?, grant*, constraint*, default*) ATTRIBUTE name string notnull bool unique bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Spalten vom Typ Date werden verwendet, um ein Datum ohne Zeit, oder Zeitzone zu verwalten.
Der physische Datentyp hängt vom gewählten DBMS ab. Für DBMS, welche diesen Typ nicht unterstützten, kann dies über den Typ Integer simuliert werden.
Beim Editieren können Selectboxen angezeigt werden, welche die Eingabe erleichtern.
Eingaben werden als Text dargestellt. Die Darstellung kann je nach gewählter Landessprache abweichen.
HTML5:
<input type="date" {required="notnull"} name="{name}"/>
ELEMENT time (description?, grant*, constraint*, default*) ATTRIBUTE name string notnull bool unique bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Spalten vom Typ Time werden verwendet, um ein Datum mit Zeit und Zeitzone zu verwalten.
Der physische Datentyp hängt vom gewählten DBMS ab. Für DBMS, welche diesen Typ nicht unterstützten, kann dies über den Typ Integer simuliert werden.
Beim Editieren können Selectboxen angezeigt werden, welche die Eingabe erleichtern.
Eingaben werden als Text dargestellt. Die Darstellung kann je nach gewählter Landessprache und Zeitzone abweichen.
HTML5:
<input type="datetime" {required="notnull"} name="{name}"/>
ELEMENT timestamp (description?, grant*, constraint*, default*) ATTRIBUTE name string notnull bool unique bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Spalten vom Typ Timestamp werden verwendet, um ein Datum mit Zeit in UTC zu verwalten.
Dieser Typ ist identisch zu Time, abgesehen von der technischen Umsetzung.
Der physische Datentyp hängt vom gewählten DBMS ab. Gewöhnlich wird der Wert als ganze Zahl gespeichert und zurückgegeben.
Beachten Sie, dass es bei einigen Betriebssystemen Probleme mit negativen Zeitstempeln geben kann, beispielsweise auf älteren Win32-Systemen.
Achten Sie darauf, nicht den Wert 0 (1.1.1970) mit NULL (undefiniert) zu verwechseln.
Beim Editieren können Selectboxen angezeigt werden, welche die Eingabe erleichtern.
Eingaben werden als Text dargestellt. Die Darstellung kann je nach gewählter Landessprache und Zeitzone abweichen.
HTML5:
<input type="datetime-local" {required="notnull"} name="{name}"/>
ELEMENT enum (description?, grant*, constraint*, default*, option+) ATTRIBUTE name string notnull bool unique bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Der Datentyp Enum ist ein "Aufzählungstyp" (Enumeration). Der Liste der gültigen Werte kann über Option-Elemente vorgeben werden.
Beachten Sie, dass der Default-Wert (falls angegeben) ein gültiges Element des Aufzählungstyps sein muss.
Aufzählungstypen werden als Texte gespeichert. Der Wert entspricht dem Attribut value der gewählten Option.
Beim Editieren wird eine Select-Box erzeugt. Alternativ können Radio-Buttons verwendet werden. Die Elemente entsprechen den Option-Elementen des Tags.
HTML5:
<select name="{name}"> <option value="">null</option> <option value="1">1</option> <option value="2">2</option> ... <option value="n">n</option> </select>
ELEMENT option (#PCDATA) ATTRIBUTE value string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
value | string | - | - | Text oder Integer-Wert für diese Option. |
Eine Option entspricht einem gültigen Element eines Aufzählungstyps. Diese hat eine Beschreibung als Text (pcdata) und einen Wert. Nur der Wert wird in der Datenbank gespeichert. Die Beschreibung (pcdata) wird nur in der Nutzeroberfläche (anstatt des Werts) angezeigt.
Die Beschreibung stellt die Option in lesbarem Text dar. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird.
Wenn ein für den Aufzählungstyp ungültiger oder undefinierter Wert in der Datenbank gefunden wird, muss in der Nutzeroberfläche genau der gespeicherte Wert anzeigt werden, ohne diesen umzuwandeln. Die Implementierung kann zusätzlich einen Fehler melden.
ELEMENT set (description?, grant*, constraint*, default*, option+) ATTRIBUTE name string notnull bool unique bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Der Datentyp "set" entspricht dem Typ "enum", gestattet es jedoch, mehrere Werte auszuwählen.
Beachten Sie, dass der Default-Wert (falls angegeben) ein gültiges Element des Aufzählungstyps sein muss.
Der physische Datentyp hängt vom gewählten DBMS ab. Einige DBMS bieten eine native Unterstützung für diesen Typ. Diese sollte verwenden werden, wenn sie verfügbar ist. Andernfalls können die Eingaben als durch Kommata getrennte Texte gespeichert werden. Die Werte entsprechen den Werten der gewählten Optionen.
Beim Editieren wird eine Liste von Checkboxes erzeugt. Alternativ kann eine Select-Box verwendet werden, welche die Auswahl mehrerer Optionen gestattet. In beiden Fällen entsprechen die Werte und Beschriftungen den Option-Elementen des Tags.
HTML5:
<label><input type="checkbox" name="{name}[]" value="1"> 1 </label> <label><input type="checkbox" name="{name}[]" value="2"> 2 </label> ... <label><input type="checkbox" name="{name}[]" value="n"> n </label>
<select multiple="multiple" name="{name}"> <option value="">null</option> <option value="1">1</option> <option value="2">2</option> ... <option value="n">n</option> </select>
ELEMENT list (description?, grant*, constraint*) ATTRIBUTE name string notnull bool unique bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Spalten vom Typ List sind numerische Arrays die als Werte Zeichenketten enthalten.
PostgreSQL bietet native Unterstützung für Arrays. Für andere DBMS muss dieses Feature simuliert werden. Dies kann implementiert werden, indem die Werte als serialisierte Zeichenfolge oder durch Kommata getrennte Aufzählung der Elemente gespeichert werden. Diese Zeichenfolge sollte, wenn sie geladen wird, deserialisiert, und als Array zurückgegeben werden.
Listen werden beim Editieren als Liste von Inputelementen dargestellt. Es wird zusätzlich ein Steuerelement zum Entfernen und Hinzufügen von Einträgen angezeigt.
Ist das Element nicht editierbar, so werden seine Elemente als Liste aufgezählt.
Die Listendarstellungen können nummeriert sein.
ELEMENT array (description?, grant*, constraint*) ATTRIBUTE name string notnull bool unique bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Eine Spalte vom Typ Array ist (möglicherweise mehrdimensionales) Array von Zeichenfolgen.
Für die meisten DBMS muss dieses Feature simuliert werden. Dies kann implementiert werden, indem die Werte als serialisierte Zeichenfolge gespeichert werden. Diese Zeichenfolge sollte, wenn sie geladen wird, deserialisiert, und als Array zurückgegeben werden. Für diesen Fall wird empfohlen, die Zeichenfolge in JSON zu kodieren.
Arrays werden beim Editieren als Paare von Schlüsseln und Werten dargestellt. Es wird zusätzlich ein Steuerelement zum Entfernen und Hinzufügen von Einträgen angezeigt.
Ist das Element nicht editierbar, so werden seine Elemente als mehrdimensionale Listen aufgezählt. Schlüssel und Werte werden optisch voneinander getrennt dargestellt. Die Darstellung kann als aufklappbares Baummenü erfolgen.
ELEMENT file (description?, grant*, constraint*) ATTRIBUTE name string notnull bool maxsize integer readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
maxsize | integer | - | - | Die maximale Größe der Datei in Bytes. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Der Datentyp "file" dient dem Speichern von Dateien ("binary large objects").
Die Dateien selbst sollten nach dem Upload aus Gründen der besseren Performance im Dateisystem verbleiben. Um Speicherplatz zu sparen, kann eine Komprimierung (z.Bsp. GZip) verwendet werden. 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.
Die Datei sollte aus Sicherheitsgründen so abgespeichert werden, dass diese für den Client nicht direkt abrufbar ist. Beim Download der Datei sollte diese automatisch entpackt werden, 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, können die Daten, falls der Browser des Nutzers diese Funktionalität anbietet, automatisch als komprimierter Datenstrom übertragen werden. Der Browser übernimmt das Entpacken selbstständig. Ein Eingreifen von Hand ist nicht erforderlich.
Beim Editieren wird ein Uploadfeld zum Hochladen einer neuen Datei und ein Link für den Download der aktuell gespeicherten Datei angezeigt. Die Implementierung kann für Dateien deren Mime-Type bekannt ist eine Vorschau anbieten.
ELEMENT image (description?, grant*, constraint*) ATTRIBUTE name string notnull bool width integer height integer ratio bool background string maxsize integer readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
width | integer | - | - | Die Breite des Bildes in Pixel |
height | integer | - | - | Die Höhe des Bildes in Pixel |
ratio | bool | - | no | Betrifft nur den Prozess des Anpassens der Größe von Bildern, für welche die Attribute height und width angegeben sind. In allen anderen Situationen muss das Attribut ignoriert werden. Hat dieses Attribut den Wert "yes", muss das Seitenverhältnis des Bildes bei der Veränderung der Größe beibehalten werden. Hat es den Wert "no", muss das Bild auf die angegebene Größe gestreckt oder gestaucht werden. |
background | hex-value | - | - | Betrifft nur den Prozess des Anpassens der Größe von Bildern, für welche das Attribut ratio auf "yes" gesetzt ist und die Attribute height und width angegeben sind. In diesem Fall können Sie die Hintergrundfarbe angeben. In allen anderen Situationen muss das Attribut ignoriert werden. Der Wert muss ein hexadezimaler Farbwert sein. Beispiel: #f0a080 |
maxsize | integer | - | - | Die maximale Größe des Bildes in Bytes. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Spalten des Typs Image sind Dateien (binary large objects). Diese müssen eine Grafik eines unterstützten Typs sein und sollten auf der Nutzeroberfläche als Bild angezeigt werden können.
Die Grafikdatei muss beim Upload automatisch geprüft und gegebenenfalls angepasst werden. Sollte die gegebene Datei keine gültige Grafik sein, muss die Implementierung einen Fehler melden. Die Anpassung der Grafik muss gemäß den Attributen "width", "height", "ratio" und "background" erfolgen. Die Größe der Grafik wird auf die angegebene Höhe und Breite angepasst. Falls das Attribut "ratio" auf "no" gesetzt ist und Breite und Höhe gegeben sind, so erfolgt eine asymmetrische Anpassung der Bildgröße auf exakt die angegeben Werte. Andernfalls wird das Bild in Höhe und/oder Breite so angepasst, dass die Bildsymmetrie (also das Seitenverhältnis) erhalten bleibt. Sollte durch diese Änderung ein leerer Teil der Canvas entstehen, so wird dieser Teil mit einer Hintergrundfarbe gefüllt. Die Hintergrundfarbe wird über das Attribut "background" angegeben. Sollte keine Hintergrundfarbe gegeben sein, so kann die Software selbstständig entscheiden, welche Farbe verwendet wird.
Beachten Sie: nicht alle Grafiken sind geeignet für die Darstellung in einem Browser. Zum Beispiel haben typischerweise viele Browser (und andere Programme) Probleme mit der Darstellung von Grafiken, welche CMYK-kodierte Farben verwenden.
Grafikdateien sollten aus Gründen der Performance außerhalb der Datenbank gespeichert werden. Eine Komprimierung von Bitmapgrafiken ist in der Regel nicht sinnvoll und sollte vermieden werden.
Eine Liste der gültigen Grafikformate und/oder Regeln für deren Interpretation werden in diesem Dokument nicht spezifiziert. Die Behandlung von Vektorgrafiken wird in diesem Dokument nicht spezifiziert.
Spalten vom Datentyp Image werden als Vorschau (Thumbnail) mit einem Uploadfeld zum Einfügen oder Ersetzen der gespeicherten Grafik dargestellt. Beim Klick auf das Thumbnail sollte die vollständige Grafik angezeigt werden. Für die Erstellung der Vorschau sollte die Implementierung ebenfalls die Attribute ratio und background berücksichtigen.
ELEMENT reference (description?, grant*, constraint*, default*) ATTRIBUTE name string table string column string label string notnull bool unique bool readonly bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diese Spalte identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
table | string | - | - | Name der Zieltabelle. |
column | string | - | - | Der Name der Zielspalte, welche die Werte der Referenz enthält (Werte müssen eindeutig sein). Die Werte in in dieser Spalte werden als Wert der Referenz gespeichert. |
label | string | - | - | Der Name einer Zielspalte, welche die Beschriftungen enthält (Werte sollten eindeutig sein). Die Spalte sollte eine lesbare Beschreibung enthalten, welche dem User angezeigt wird. |
notnull | bool | - | no | Eine Spalte, die mit not-null definiert ist, darf keine undefinierten (NULL-)Werte enthalten. |
unique | bool | - | no | Ein Unique-Constraint bedeutet , dass die Spalte keinen Wert mehrfach enthalten darf. Beachten Sie, dass ein Unique-Constraint technisch einen Unique-Index auf dieser Spalte impliziert und umgekehrt. |
readonly | bool | - | no | Sie können die Spalte auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Hinweis: Zeilen können weiterhin hinzugefügt oder gelöscht werden, jedoch darf die Spalte nicht aktualisiert werden. |
title | string | - | - | Ein Text welcher in der Nutzeroberfläche zur Beschriftung des mit der Spalte verbundenen Steuerelementes verwendet werden kann. Beachten sie, dass der Text ein Platzhalter sein darf, welcher für die angezeigte Sprache übersetzt wird. |
Spalten vom Typ Reference werden verwendet um Fremdschlüssel zu repräsentieren. Der echte Typ der Spalte hängt vom Typ der Zielspalte ab.
Eine Referenz impliziert nicht automatisch einen Foreign-Key-Constraint.
Nur der Wert wird in der Datenbank gespeichert. Der physische Typ und die Eigenschaften der Spalte werden daher von der in die Zielspalte geerbt. Wenn der physische Typ der Zielspalte sich ändert, muss sich der physische Typ der Referenzspalte auch ändern. Wenn die Zielspalte keinen passenden Typ hat, muss die Implementierung einen Fehler melden.
Beim Editieren wird eine Select-Box erzeugt. Das Menü wird mit den Einträgen der verlinkten Tabelle aufgefüllt. Die Beschriftungen werden aus der Spalte "label" und die Werte aus der Spalte "column" in der Zieltabelle entnommen.
ELEMENT foreign (key+) ATTRIBUTE name string table string match string ondelete string onupdate string deferrable bool
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | - | - | Ein eindeutiger Name welcher diesen Foreign-Key-Constraint identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
table | string | ja | - | Name der Zieltabelle. |
match | string | - | simple | full | partial | simple |
ondelete | string | - | no-action | no-action | restrict | cascade | set-null | set-default |
onupdate | string | - | no-action | no-action | restrict | cascade | set-null | set-default |
deferrable | bool | - | no | Deferrable bedeutet, dass der DBS bis zum Ende der Transaktion warten sollte, bevor hinzugefügte oder aktualisierte Fremdschlüssel geprüft werden. Das wird in Situationen verwendet, in denen Daten innerhalb einer Transaktion sowohl in die Eltern- als auch in die Kindtabelle eingefügt werden, oder wenn kreisförmige Referenzen erzeugt werden (sofern das DBMS dies unterstützt). |
Fremdschlüssel dienen dazu, referentielle Integrität zwischen Tabellen zu gewährleisten. Dieses Feature wird nicht von allen DBMS unterstützt. Die Implementierung kann dieses Feature emulieren.
Jeder Fremdschlüssel besteht aus mindestens einer Quelle und einem Ziel. Beachten Sie, dass die Datentypen der Quellspalten eines Fremdschlüssels von den Datentypen der Zielspalten abhängen. Spalten, welche einen Fremdschlüssel enthalten, sollten als Typ "reference" definiert werden. In diesem Fall muss die Implementierung den korrekten Datentyp automatisch festlegen.
Die Attribute "ondelete" und "onupdate" definieren, wie das DBMS auf eine Änderung der Referenz reagieren soll.
Das Attribut "match" definiert, wann das DBMS die referentielle Integrität als erfüllt betrachten soll. Dies betrifft nur zusammengesetzte Fremdschlüssel, welche mehrere Spalten verwenden.
Das Attribut "deferrable" wird von einigen DBMS nicht unterstützt. Beachten Sie, dass diese Eigenschaft nicht simuliert werden kann. Verschiedene DBMS haben verschiedene Herangehensweisen, um dieses Problem zu umgehen. Z.Bsp. das vorübergehende Deaktivieren von Constraints. Nähere Informationen finden Sie in Ihrem Handbuch.
Das Attribut "match" wird durch einige DBMS nicht unterstützt. Dies betrifft nur zusammengesetzte Fremdschlüssel, welche mehrere Spalten verwenden. Dieses Feature wird selten verwendet und sollte für Datenbankanwendungen aus Gründen der Kompatibilität vermieden werden.
Einige Werte der Attribute "onupdate" und "ondelete" werden durch einige DBMS nicht unterstützt. Diese können simuliert werden durch die Verwendung von Trigger.
ELEMENT key EMPTY ATTRIBUTE name string column string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Name der Spalte in der Quelltabelle. |
column | string | - | - | Name der Spalte in der Zieltabelle. Der Default-Wert ist der Primärschlüssel der Zieltabelle. |
Eine Referenz einer Quell- auf eine Zielspalte. Wenn ein Fremdschlüssel mehr als eine Referenz definiert, handelt es sich um einen sogenannten "zusammengesetzten" Fremdschlüssel (compound foreign key). Beachten Sie, dass zusammengesetzte Schlüssel sehr kompliziert in der Verarbeitung sind, und nicht von allen DBMS unterstützt werden. Zusammengesetzte Schlüssel sollten wenn möglich vermieden werden.
ELEMENT index (description?, column*) ATTRIBUTE name string unique bool clustered bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | - | - | Ein eindeutiger Name welcher diesen index identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
unique | bool | - | no | Ein Unique-Index impliziert stets einen Unique-Constraint. Ein Unique-Constraint bedeutet, dass die Spalte keinen Wert mehrfach enthalten darf. |
clustered | bool | - | no | Besagt, dass alles Spalten im Tablespace in der Reihenfolge dieses Index gespeichert werden sollen. Das ist eine Einstellung zur Verbesserung der Performance. |
title | string | - | - | Title ist ein Beschriftungstext, der in der Nutzeroberfläche angezeigt werden sollte wenn das Objekt anzeigt wird. |
Indexes werden verwendet, um die Leistung von Abfragen zu verbessern. Ein Index ist eine sortierte Liste von Spaltenwerten. Das Durchsuchen eines Index ist gewöhnlich schneller als die Suche über eine ganze Tabelle. Jedoch: das Erzeugen und Verwalten eines Indexes erzeugt einen Overhead an Rechenzeit, Insert- und Update-Anweisungen werden daher langsamer wenn Indexe verwendet werden.
Beachten Sie: es ist nicht erforderlich einen Unique-Constraint auf einen Primärschlüssel explizit anzulegen. Primärschlüssel haben bereits implizit einen Unique-Constraint.
Wichtig! Selbst wenn ein Unique-Index besteht, muss die Implementierung nicht unbedingt melden, dass die Spalte einen Unique-Constraint besitzt. Es wird empfohlen Unique-Indexes nicht zu verwenden, wenn das Gleiche mit einem Constraint ausgedrückt werden kann. Beachten Sie, dass ein Unique-Constraint nicht über mehrere Spalten definiert werden kann. In diesem Fall sollten Sie einen Unique-Index verwenden.
Clustered Indexes betreffen ausschließlich MSSQL. Ein clustered Index bedeutet, dass der DBS versuchen soll, Werte die im Index nah beieinander liegen auch im Tablespace nah beieinander abzulegen, damit diese beim Lesen der Tabelle in den gleichen Speicherblock passen.
In den meisten Fällen würde erwartet, dass ein clustered Index auf dem Primärschlüssel erzeugt wird (dies ist ohnehin der Standardfall), oder auf einer stattdessen zur Sortierung verwendeten Spalte. Pro Tabelle darf nur ein clustered Index angelegt werden.
Wenn das Attribut clustered eines Index auf "yes" gesetzt wird, dann muss die Implementierung prüfen, ob in der Tabelle bereits ein anderer clustered Index definiert ist.
Falls dies der Fall ist, so muss das Attribut clustered dieses Index auf "no" gesetzt werden.
Die Implementierung kann einen Fehler melden, wenn zwei clustered Indexes in einer Tabelle gefunden werden.
ELEMENT column EMPTY ATTRIBUTE name string sorting string length string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Name der indexierten Spalte in der Quelltabelle. |
sorting | string | - | ascending | In einem Index kann zum Zweck der Optimierung jede Spalte getrennt auf- oder absteigend sortiert werden. Das wird insbesondere für Indexe über mehrere Spalten verwendet.
|
length | integer | - | - | maximale Länge der im Index gespeicherten Werte |
Die Liste der in einem Index hinterlegten Spalten gibt an, welche Spalten einer Tabelle in den Index aufgenommen, und wie diese Werte gespeichert werden.
Das Attribut length dient der Optimierung der Performance und wird nur in MySQL verwendet. Andere DBMS unterstützen dieses Argument nicht. Beachten Sie, dass das Attribut length nicht größer sein darf als die Länge der Quellspalte.
Die Implementierung kann automatisch entscheiden, ob ein Volltextindex angelegt werden soll, falls das DBMS dieses Feature unterstützt.
ELEMENT view (description?, grant*, field+, select*)> ATTRIBUTE name string readonly bool tables string where string orderby string sorting string checkoption string title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher diesen View identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
readonly | boole | - | no | Sie können den View auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Ein View, welcher schreibgeschützt ist, kann nicht aktualisiert werden (ist nicht updatable). |
tables | nmtokens | - | - | Eine durch Kommata getrennte Liste von Tabellen, welche im aktuellen View verwendet werden.
Wenn die Liste mehr als eine Tabelle enthält, so ist die erste die Basistabelle, und alle weiteren Tabellen werden mit dieser über einen Join verknüpft. Vergessen Sie nicht eine Where-Klausel für die verknüpften Tabellen zu definieren. |
where | string | - | - | Das ist eine generische Information. Sie setzt die Where-Klausel des Views. |
orderby | string | - | - | Eine durch Kommata getrennte Liste von Spalten, nach denen die Ausgabe sortiert wird. Standardmäßig wird nach dem Primärschlüssel der Tabelle sortiert. |
sorting | string | - | ascending |
|
checkoption | string | - | none |
|
title | string | - | - | Title ist ein Beschriftungstext, der in der Nutzeroberfläche angezeigt werden sollte wenn das Objekt anzeigt wird. |
Das "View"-Element definiert den Namen, die Dokumentation und allgemeine Eigenschaften eines Datenbank-Views. Dies sind seine Basistabellen, Where-Klausel und andere Informationen, welche es einer Anwendung erlauben sollen, die Elemente des Views einer echten Tabelle zuzuordnen. Dies sollte es einer Implementierung ermöglichen, einfache und updatable Views für solche DBMS zu simulieren, welche dieses Feature nicht unterstützen. Eine Implementierung kann die Simulation von Views mit Hilfe der generischen Informationen unterstützen. Die Implementierung kann einen Fehler melden, falls es ihr nicht möglich ist einen View zu simulieren und das DBMS das geforderte Feature nicht unterstützt.
Die Implementierung muss einen View als "updatable" (aktualisierbar) betrachten, sofern das Attribut "readonly" nicht auf "yes" gesetzt ist. Sie kann jedoch entscheiden, dass ein View keine Änderungen erlaubt, wenn ein erforderlicher Primärschlüssel fehlt. Wo dies möglich ist kann die Implementierung automatisch einen Primärschlüssel zur generischen Abfrage hinzunehmen, um den View updatable zu machen. Für DBMS, welche updatable Views nicht unterstützen, kann die Implementierung diese simulieren, indem sie Insert- oder Update-Anweisungen basierend auf den gegebenen generischen Informationen selbst erzeugt. Die Implementierung kann einen Fehler melden, wenn der Nutzer versucht einen View für ein betroffenes DBMS zu ändern und sie nicht in der Lage ist, das gewünschte Verhalten zu simulieren.
Das Attribut "where" definiert die Where-Klausel des Views. Diese Information muss bei der Simulation des Views beachtet werden. Eine Implementierung kann die korrekte Syntax für dieses Element selbst definieren. Beachten Sie! Folgende Schreibweise wird nicht empfohlen "time < now()" weil die Funktion "now()" zwischen verschiedenen DBMS nicht kompatibel ist. Sie können jedoch zusätzlich abweichende SQL-Abfragen für ein bestimmtes Ziel-DBMS Ihrer Wahl definieren. Die vom Yana Framework unterstützte Syntax für generische Where-Klauseln ist: {[column]=[value]{ AND [column]=[value]}*}.
Das Attribut "checkoption" steuert die Auswertung der Where-Klausel. Der Unterschied zwischen 'local' und 'cascaded' betrifft nur Situationen, in denen ein View rekursiv auf einem anderen View aufgebaut wird und der Elternview selbst einen Constraint (Check-Option) definiert. In diesem Fall hindert die Einstellung 'local' den DBS daran, die Check-Option(en) des Elternviews rekursiv zu prüfen. Beachten Sie, dass diese Einstellung nicht von allen DBMS unterstützt wird.
Z.Bsp. wird von MySQL und PostgreSQL dieses Feature unterstützt , während MSSQL keine Unterstützung bietet.
ELEMENT select (#PCDATA) ATTRIBUTE dbms string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
dbms | string | - | generic | Der Name des Ziel-DBMS. Der Wert "generic" bedeutet, dass die Definition für jedes DBMS zutreffend ist. Gewöhnlich wird das als Rückfalloption für DBMS verwendet, an welche Sie entweder beim Erstellen der Datenbankstruktur noch nicht gedacht haben, oder welche das fragliche Feature nicht unterstützen. |
Das "select" Element ist eine DBMS-abhängige SQL-Anweisung. Diese muss den definierten Namen der Basistabellen, Spalten und anderen View-Eigenschaften entsprechen. Für einfache Views kann die generische Information bereits ausreichend sein, so dass keine zusätzlichen Select-Elemente angegeben werden müssen. Daher sollte das Select-Element falls möglich vermieden werden.
ELEMENT field EMPTY ATTRIBUTE table string column string alias string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
table | string | - | - | Name der Basistabelle |
column | string | - | - | Name der Basisspalte |
alias | string | - | - | optionaler Alias |
Eine Spaltenreferenz, welche den Namen einer Spalte im View (siehe Attribut "alias") dem Namen der physischen Tabelle und Spalte zuordnet, auf welcher diese basiert.
ELEMENT form (description?, grant*, input*, form*, event*) ATTRIBUTE name string table string template string key string allinput bool title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher dieses Formular identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
name | string | ja | - | Ein eindeutiger Name welcher dieses Formular identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
table | string | - | - | Name einer Quelltabelle oder eines Views. Beachten Sie, dass der View updatable sein sollte. Andernfalls sollte das Formular nicht editierbar sein. |
template | string | - | - | Das Attribut template kann einen beliebigen Text enthalten. Die Implementierung zur Generierung des Formulars kann eine Liste gültiger Werte für dieses Attribut festlegen. Das Template sollte alle erforderlichen Informationen liefern, welche die Implementierung zur Darstellung des Formulars benötigt. |
key | string | - | - | Für jedes eingebettete Subformular gilt, dass dessen Basistabelle über einen Fremdschlüssel direkt mit der Basistabelle des Elternformulars verbunden sein muss. Sollte es mehrere passende Fremdschlüssel geben, so kann das Attribut key angeben, über welchen Fremdschlüssel die Tabellen verknüpft werden sollen. Fehlt das Attribut key, so muss die Implementierung den ersten passenden Fremdschlüssel verwenden. Die Implementierung kann einen Fehler melden, falls kein passender Fremdschlüssel existiert, oder das Attribut key auf einen ungültigen Fremdschlüssel verweist. |
allinput | bool | - | no | Das Attribut allinput gibt an, ob beim Erzeugen des Formulars automatisch nicht definierte Spalten der Basistabelle in das Formular übernommen werden sollen. Dies dient dazu redundante Angaben zu vermeiden. Hat dieses Attribut den Wert "yes", so muss die Implementierung für alle fehlenden Tabellenspalten im Formular Input-Elemente mit der Default-Belegung erstellen. Die Namen der Elemente müssen den Spaltennamen entsprechen. |
title | string | - | - | Title ist ein Beschriftungstext, der in der Nutzeroberfläche angezeigt werden sollte wenn das Objekt anzeigt wird. |
Formulare sind benannte Objekte, welche als Eingabe für Formular- und Oberflächengeneratoren benutzt werden. Sie müssen mindestens eine Basistabelle und ein Template festlegen. Die Basistabelle darf natürlich auch ein (updatable) View sein.
Formulare sind kein Feature der Datenbank. Sie müssen für alle bekannten DBMS durch Software generiert werden. Der Inhalt des Formulars basiert jedoch auf dem Datenbankschema, welches in der XDDL-Datei definiert ist. Basierend auf diesen Informationen sollte die Implementierung Select-, Update-, Insert- oder Delete-Anweisungen selbstständig generieren.
In einer Ausgabe als HTML, sollten Formulare als Form-Elemente angezeigt werden. Die Darstellung des Formulars muss im mit dem Form-Element verbundenen Template definiert sein.
Formulare dürfen verschachtelt sein und Subformulare enthalten, deren Elemente aus der gleichen, oder anderen Tabellen stammen können. Eingebettete Subformulare können kurch Verwendung des Tags "fieldset" dargestellt werden. Das Attribut title kann als Wert für ein "legend"-Element des Tags verwendet werden.
ELEMENT input (description?, grant*, event*) oder, falls das Input-Element sich auf keine Tabellenspalte in der Datenbank beziehen soll: ELEMENT input ( (array | bool | color | date | enum | file | float | html | image | inet | integer | list | mail | password | range | reference | set | string | text | time |timestamp | url), event*) ATTRIBUTE name string label string hidden bool readonly bool cssclass string tabindex integer
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher das Formularfeld identifiziert. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
label | string | - | - | Das Attribut label ist ein Beschriftung welche Informationen zum Inhalt des Formularfelds liefert. |
hidden | bool | - | no | Das Formularfeld darf in der Nutzeroberfläche nicht sichtbar sein, wenn der Wert dieses Attributs auf "yes" gesetzt wird. Andernfalls soll das Attribut ignoriert werden. |
readonly | bool | - | no | Sie können das Formularfeld auf schreibgeschützt setzen, um zu verhindern dass Änderungen vorgenommen werden. Ein Formularfeld, welches schreibgeschützt ist, kann nicht editiert werden. |
cssclass | string | - | - | Eine HTML-basierte Nutzeroberfläche sollte Id-Attribute und CSS-Klassen für Formularfelder automatisch bereitstellen. Zusätzlich kann dieses Attribut verwendet werden um eine nutzerdefinierte CSS-Klasse hinzuzufügen. |
tabindex | integer | - | 0 | Eine HTML-basierte Nutzeroberfläche sollte den Tab-Index für Formularfelder automatisch erstellen. Alternativ kann dieses Attribut verwendet werden um einen nutzerdefinierten Wert festzulegen. Der Tab-Index definiert die Reihenfolge, in welcher Formularfelder den Eingabefokus erhalten, wenn der Nutzer die Tabulatortaste des Keyboards drückt. |
Das Input-Element bezeichnet ein einzelnes Formularfeld.
Wenn sich dabei auf ein echtes Feld in der Datenbank bezogen wird, so bezeichnet das Attribut "name" den Namen der Spalte. Andernfalls muss die Spalte innerhalb des Elements direkt deklariert werden.
Eine HTML-basierte Nutzeroberfläche sollte dies darstellen als "input"-Element oder etwas vergleichbares, abhängig vom Typ der zugrundeliegenden Spalte. Wenn das Attribute "readonly" auf "yes" gesetzt ist, sollte das Element nicht editierbar sein. Die Implementierung sollte CSS Class- und/oder Id-Attribute für jedes Formularfeld automatisch erzeugen. Zusätzlich muss, wenn das Attribut "cssclass" gesetzt wird, dieser Wert zum Attribut Class des Tags hinzugefügt werden. Wenn das Attribut "tabindex" angegeben ist, muss es in die Attributliste des Steuerelements kopiert werden. Falls das "input"-Element durch mehr als ein HTML-Element umgesetzt wird, so muss das Attribut tabindex auf das erste editierbare Feld gesetzt werden.
ELEMENT event (#PCDATA) ATTRIBUTE name string language string title string label string icon image
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Ein eindeutiger Name welcher das Ereignis identifiziert. Sollte kleingeschrieben und ein gültiger Funktionsname sein. |
language | string | - | - | Die Programmiersprache in welcher die Ereignisbehandlung implementiert ist. Kann eine beliebige Zeichenkette sein. Falls diese Option nicht angegeben ist, kann die Implementierung selbst festlegen, wie das Ereignis zu behandeln ist. Das Yana Framework wird den Bereich PCDATA in diesem Fall als Namen einer statischen Methode in PHP interpretieren, welche die Ereignisbehandlung implementiert. |
title | string | - | - | Attribut title zur Verwendung in anklickbaren Links. |
label | string | - | - | Beschriftung von anklickbaren Links. |
icon | image | - | - | Grafikdatei zur Verwendung als Icon für anklickbare Links. |
Das Ereignis wird ausgelöst, wenn der Benutzer im angezeigten Formular eine bestimmte Aktion auslöst, wie das Absenden des Formulars, das Anklicken eines Downloads, oder was vergleichbares. Die verfügbaren Typen von Ereignissen müssen durch das gewählte Template definiert werden. Die Implementierung kann selbst definieren, wie das Ereignis ausgewertet werden soll. Das Attribut "name" definiert den Namen des Ereignisses, und der PCData-Abschnitt den Namen der aufzurufenden Funktion.
Beispiel: Ereignis "submit" mit PCData "foo" wird die Formulardaten über die Methode POST zur Server-Anwendung mit der URL "?action=foo" senden, wenn der Benutzer das Formular absendet (den "submit" Button betätigt). Die Implementierung muss definieren, was "submit" für im Falle des angegebenen Formulartemplates tatsächlich bedeutet.
Die Darstellung des Elements hängt von den Attributen language und name ab.
Für die Sprache PHP, oder wenn das Attribut language leer ist, wird empfohlen zur Darstellung einen "A"-Tag neben dem Formularfeld zu verwenden. Der Inhalt des HTML-Tags besteht aus dem Attribut label und/oder einem Image-Tag, dessen Attribut "src" aus dem Attribut "icon" übernommen wird. Das Attribute "href" des HTML-Tags sollte eine Referenz auf PHP_SELF und den Namen der Aktion als Parameter beinhalten, in der Form "action={name}". Als Wert des Feldes sollte als zweiter Parameter "target[{primärschlüssel}]={wert}" angegeben werden.
Beispiel:
<action name="foo" label="klick mich" icon="common_files/icon.png"/> <a href="?action=foo&target[12]=bar"> klick mich <img src="common_files/icon.png"/> </a>
Für die Sprache JavaScript, muss das Attribut name eine gültige Bezeichnung für ein Ereignis in JavaScript sein, und der Abschnitt PCDATA muss gültigen JavaScript-Code enthalten.
Beispiel:
<action name="onchange" language="javascript">validate(this)</action> <input ... onchange="validate(this)"/>
Wenn ein "label" oder "icon" angegeben sind, soll die Aktion ausgeführt werden wenn das "label" und/oder "icon" angeklickt worden sind.
Beispiel:
<action name="onchange" label="prüfen" icon="common_files/validate.png" language="javascript">validate('foo')</action> <input ... onchange="validate('foo')" /> <a onclick="validate('foo')"> prüfen <img src="common_files/validate.png"/> </a>
Die Umsetzung kann alternativ als Button erfolgen.
Beispiel:
<action name="submit" label="abschicken" title="Klick mich!" icon="common_files/submit.png" language="php">foo</action> <button type="submit" title="Klick mich!" name="foo"> <img src="common_files/submit.png"/> abschicken </button>
ELEMENT function (description?, implementation+) ATTRIBUTE name string title string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Name der Funktion. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
title | string | - | - | Title ist ein Beschriftungstext, der in der Dokumentation des Objektes angezeigt werden sollte. |
Eine nutzerdefinierte Funktion mit dem angegebenen Namen. Die Funktion darf maximal eine Implementierung für jedes unterstützte DMBS geben.
ELEMENT implementation (param*, return?, code) ATTRIBUTE dbms string language string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
dbms | string | - | generic | Der Name des Ziel-DBMS. Der Wert "generic" bedeutet, dass die Definition für jedes DBMS zutreffend ist. Gewöhnlich wird das als Rückfalloption für DBMS verwendet, an welche Sie entweder beim Erstellen der Datenbankstruktur noch nicht gedacht haben, oder welche das fragliche Feature nicht unterstützen. |
language | string | - | - | Die vorgesehene Programmiersprache. Dies betrifft nur DBMS, welche mehr als eine Sprache unterstützen. |
Die Implementierung definiert die Funktionssignatur und den Quellcode. Die Anzahl der Parameter muss in jedes DBMS (und jedes Implementation-Element) identisch sein.
Falls das Attribut dbms auf "generic" gesetzt ist, kann die XDDL-Implementierung entscheiden, ob die generische Definition der Funktion kompatibel mit einem bestimmten DBMS ist. Falls diese entscheidet, dass die Definition nicht kompatibel ist, kann sie versuchen die Funktion zu simulieren. Für diesen Fall kann die Implementierung die erforderliche Syntax für die Unterelemente "code", "param" und "return" selbst festlegen. Falls die Definition der erforderlichen Syntax nicht entspricht, kann die XDDL-Implementierung einen Fehler melden.
Beachten Sie, dass das Attribut "language" DBMS-abhängig ist. Die meisten DBMS sollten zumindest die Sprache "SQL" unterstützen, während andere auch "Java", "C" oder auch mehr unterstützen können.
Wenn keine Sprache gegeben wird, wird die default Sprache verwendet. Beachten Sie, dass die Implementierung nicht prüfen muss, ob die angegebene Sprache vom angegebenen DBMS unterstützt wird.
Für simulierte Funktionen muss das Attribut language leer sein.
ELEMENT param EMPTY ATTRIBUTE name string type string mode string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | eindeutige Parameterbezeichnung |
type | string | ja | - | DBMS-abhängiger Datentyp |
mode | string | - | in | Das Attribute "mode" identifiziert das Element als
|
Eine Parameterdefinition als ein Teil der Funktionssignatur. Das Attribut "mode" definiert das Verhalten des Parameters. Der Typ des Parameters ist vom DBMS abhängig.
Beispiel:
<function name="foo"> <implementation> <param name="p1" type="string" mode="in"/> <param name="p2" type="float" mode="inout"/> <param name="p3" type="int" mode="out"/> <return>int</return> <code>...</code> </implementation> </function> Kann interpretiert werden als: int foo ( string $p1, float &$p2, int &$p3 = null ) { ... }
Beachten Sie, dass manche DBMS nur Eingabeparameter (Wertparameter) unterstützen. In diesem Fall muss das Attribut mode den Wert "in" haben. Die Implementierung kann einen Fehler melden, wenn eine nicht unterstützte Definition gefunden wird.
ELEMENT return (#PCDATA)
Der durch die Funktion zurückgegebene Datentyp. Diese Einstellung ist DBMS-abhängig.
Wenn kein Rückgabewert definiert, oder die Angabe leer ist, so wird der Defaultwert "void" verwendet, was bedeutet, dass die Funktion keinen Wert zurückgibt. Falls die Funktion mehr als einen Wert zurückgeben muss, sollten stattdessen Ausgabeparameter (mode=out) verwendet werden.
Beachten Sie, dass in MySQL Funktionen, die keinen Rückgabewert haben, "Methoden" genannt werden.
ELEMENT code (#PCDATA)
Der Funktionsrumpf. Die Syntax des Inhaltes hängt von den Parametern für DBMS und Programmiersprache ab. Wenn das DBMS auf "generic" gesetzt ist, dann wird dieser Code durch die Server-Anwendung ausgeführt. Für diesen Fall kann die Implementierung die erforderliche Syntax selbst festlegen. Es wird empfohlen, dass das Element code darauf beschränkt wird, den Namen einer Funktion anzugeben, welche die Implementierung aufrufen kann. Alle Eingabeparameter werden an diese Funktion weitergeleitet. Beachten Sie, dass generische Funktionen innerhalb von SQL-Anweisungen nicht verwendet werden können, weil diese nicht vom DBMS ausgeführt werden.
Das Element changelog einer Datenbankdefinition wird benutzt, um Änderungen zu dokumentieren. Updates müssen in absteigender Reihenfolge nach ihrer Versionsnummer sortiert sein. Dies bedeutet, dass das erste Element stets der letzten Änderung entspricht.
Die Aktualisierungen enthalten den Typ der Änderung, eine Versionsnummer, und das geänderte Element. Eine Beschreibung der Änderung kann als PCDATA hinzugefügt werden.
Das ChangeLog kann für automatisierte Aktualisierungen der Datenbank verwendet werden. Der Implementierung kann eine Anwendung zur Verfügung stellen, welche das ChangeLog analysiert und das Schema der Datenbank von einer gegebenen Versionsnummer auf eine spätere Version aktualisiert. Diese Implementierung sollte versuchen, alle Änderungen innerhalb einer Transaktion durchzuführen. Im Fall eines nicht behebbaren Fehlers, sollte sie versuchen, sämtliche Änderungen zurückzunehmen.
ELEMENT create (description?) ATTRIBUTE name string subject string version string ignoreError bool
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Eindeutiger Name des geänderten Objektes. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
subject | string | ja | - | table | column | index | view | sequence | trigger | constraint |
version | string | - | - | Die Version, auf welche sich der Eintrag bezieht. |
ignoreError | bool | - | no | Wird verwendet, um der Funktion, welche die Aktualisierung durchführt, mittzuteilen, wie diese reagieren soll, falls dieser Schritt während der Aktualisierung der Datenbankstruktur einen Fehler verursacht. Für den Wert "yes" sollte die Aktualisierung der Datenbank fortgesetzt werden, selbst wenn dieser Schritt fehlschlägt. Für den Wert "no" sollte die Aktualisierung gestoppt und alle vorherigen Änderungen zurückgenommen werden. |
Dokumentiert die Erstellung eines neuen Datenbankelements. Der Typ des Elements wird als Attribut "subject" gespeichert. Das Element selbst wird über das Attribut "name" identifiziert. Der Name muss ein eindeutiger Bezeichner des Elements sein. Wo erforderlich muss dieser die Namensräume spezifizieren, innerhalb derer der Name des Elements eindeutig ist. In diesem Fall muss das Zeichen "." als Trennzeichen verwendet werden. Die Implementierung kann einen Fehler melden, wenn das Element nicht gefunden wurde oder nicht eindeutig ist. Das Description-Element kann zu Dokumentationszwecken verwendet werden und beliebigen Text enthalten.
ELEMENT rename (description?) ATTRIBUTE name string subject string version string ignoreError bool oldname string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Eindeutiger Name des geänderten Objektes. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
subject | string | ja | - | table | column | index | view | sequence | trigger | constraint |
version | string | - | - | Die Version, auf welche sich der Eintrag bezieht. |
ignoreError | bool | - | no | Wird verwendet, um der Funktion, welche die Aktualisierung durchführt, mittzuteilen, wie diese reagieren soll, falls dieser Schritt während der Aktualisierung der Datenbankstruktur einen Fehler verursacht. Für den Wert "yes" sollte die Aktualisierung der Datenbank fortgesetzt werden, selbst wenn dieser Schritt fehlschlägt. Für den Wert "no" sollte die Aktualisierung gestoppt und alle vorherigen Änderungen zurückgenommen werden. |
oldname | string | - | - | Vorheriger Name des umbenannten Objektes. Hinweis: Für Tabellenspalten muss der Name den Namen der Tabelle enthalten ("table.column"). |
Dokumentiert die Umbenennung eines existierenden Datenbankelements. Der Typ des Elements wird als Attribut "subject" gespeichert. Das Element selbst wird über das Attribut "name" identifiziert. Der vorherige Name des Elements wird als Attribut "oldname" gespeichert. Der Name muss ein eindeutiger Bezeichner des Elements sein. Wo erforderlich muss dieser die Namensräume spezifizieren, innerhalb derer der Name des Elements eindeutig ist. In diesem Fall muss das Zeichen "." als Trennzeichen verwendet werden. Die Implementierung kann einen Fehler melden, wenn das Element nicht gefunden wurde oder nicht eindeutig ist. Das Description-Element kann zu Dokumentationszwecken verwendet werden und beliebigen Text enthalten.
ELEMENT drop (description?) ATTRIBUTE name string subject string version string ignoreError bool
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Eindeutiger Name des geänderten Objektes. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
subject | string | ja | - | table | column | index | view | sequence | trigger | constraint |
ignoreError | bool | - | no | Wird verwendet, um der Funktion, welche die Aktualisierung durchführt, mittzuteilen, wie diese reagieren soll, falls dieser Schritt während der Aktualisierung der Datenbankstruktur einen Fehler verursacht. Für den Wert "yes" sollte die Aktualisierung der Datenbank fortgesetzt werden, selbst wenn dieser Schritt fehlschlägt. Für den Wert "no" sollte die Aktualisierung gestoppt und alle vorherigen Änderungen zurückgenommen werden. |
version | string | - | - | Die Version, auf welche sich der Eintrag bezieht. |
Dokumentiert die Löschung eines existierenden Datenbankelements. Der Typ des Elements wird als Attribut "subject" gespeichert. Das Element selbst wird über das Attribut "name" identifiziert. Der Name muss ein eindeutiger Bezeichner des Elements sein. Wo erforderlich muss dieser die Namensräume spezifizieren, innerhalb derer der Name des Elements eindeutig ist. In diesem Fall muss das Zeichen "." als Trennzeichen verwendet werden. Die Implementierung kann einen Fehler melden, wenn das Element nicht gefunden wurde oder nicht eindeutig ist. Das Description-Element kann zu Dokumentationszwecken verwendet werden und beliebigen Text enthalten.
Eine typische Situation, in welcher das Attribut "ignoreError" mit dem Wert "yes" üblicherweise verwendet wird ist die Löschung eines Elements. Gewöhnlich soll eine Datenbankaktualisierung nicht fehlschlagen, wenn ein Element nicht gelöscht werden kann, weil es nicht (mehr) existiert.
Beachten Sie, dass einige DBMS außer Stande sind, gelöschte Datenbankelemente wiederherzustellen. Im Fehlerfall kann diese Einschränkung Auswirkungen auf das Verhalten der Implementierung haben, welche die Datenbankstruktur aktualisiert.
ELEMENT update (description?) ATTRIBUTE name string subject string version string ignoreError bool property string value string oldvalue string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | ja | - | Eindeutiger Name des geänderten Objektes. Sollte kleingeschrieben und ein valider XML-, SQL-Bezeichner sein. |
subject | string | ja | - | table | column | index | view | sequence | trigger | constraint |
version | string | - | - | Die Version, auf welche sich der Eintrag bezieht. |
ignoreError | bool | - | no | Wird verwendet, um der Funktion, welche die Aktualisierung durchführt, mittzuteilen, wie diese reagieren soll, falls dieser Schritt während der Aktualisierung der Datenbankstruktur einen Fehler verursacht. Für den Wert "yes" sollte die Aktualisierung der Datenbank fortgesetzt werden, selbst wenn dieser Schritt fehlschlägt. Für den Wert "no" sollte die Aktualisierung gestoppt und alle vorherigen Änderungen zurückgenommen werden. |
property | string | - | - | Gibt an welche Eigenschaft des Objektes aktualisiert worden ist. |
value | string | - | - | Der neue Wert der Eigenschaft, welche aktualisiert wird. Die Syntax dieses Attributs kann durch die Implementierung festgelegt werden. Der Wert kann ein serialisierter Text sein. |
oldvalue | string | - | - | Der alte Wert der geänderten Eigenschaft. Die Syntax dieses Attributs kann durch die Implementierung festgelegt werden. Der Wert kann ein serialisierter Text sein. |
Dokumentiert die Änderung eines existierenden Datenbankelements. Der Typ des Elements wird als Attribut "subject" gespeichert. Das Element selbst wird über das Attribut "name" identifiziert. Der Name muss ein eindeutiger Bezeichner des Elements sein. Wo erforderlich muss dieser die Namensräume spezifizieren, innerhalb derer der Name des Elements eindeutig ist. In diesem Fall muss das Zeichen "." als Trennzeichen verwendet werden. Die Implementierung kann einen Fehler melden, wenn das Element nicht gefunden wurde oder nicht eindeutig ist. Das Description-Element kann zu Dokumentationszwecken verwendet werden und beliebigen Text enthalten. Wo verfügbar kann die geänderte Eigenschaft (property), sowie deren alter (oldvalue) und neuer Wert (value) angegeben werden.
ELEMENT sql (description?, code) ATTRIBUTE version string ignoreError bool dbms string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
dbms | string | - | generic | Der Name des Ziel-DBMS. Der Wert "generic" bedeutet, dass die Definition für jedes DBMS zutreffend ist. Gewöhnlich wird das als Rückfalloption für DBMS verwendet, an welche Sie entweder beim Erstellen der Datenbankstruktur noch nicht gedacht haben, oder welche das fragliche Feature nicht unterstützen. |
version | string | - | - | Die Version, auf welche sich der Eintrag bezieht. |
ignoreError | bool | - | no | Wird verwendet, um der Funktion, welche die Aktualisierung durchführt, mittzuteilen, wie diese reagieren soll, falls dieser Schritt während der Aktualisierung der Datenbankstruktur einen Fehler verursacht. Für den Wert "yes" sollte die Aktualisierung der Datenbank fortgesetzt werden, selbst wenn dieser Schritt fehlschlägt. Für den Wert "no" sollte die Aktualisierung gestoppt und alle vorherigen Änderungen zurückgenommen werden. |
Dokumentiert eine nutzerdefinierte SQL-Anweisung, welche ausgeführt werden soll. Die Ausführung kann auf einen bestimmten DBMS beschränkt werden. SQL-Anweisungen können für jegliche weiteren Aktionen verwendet werden, welche durch andere Elemente dieser Definition nicht abgedeckt sind. Z.Bsp. um Daten in eine kürzlich erstellte Tabelle zu kopieren. Das Description-Element kann zu Dokumentationszwecken verwendet werden und beliebigen Text enthalten. Das Code-Element muss den SQL-Code enthalten.
ELEMENT code (#PCDATA)
Enthält den auszuführenden SQL-Code. Die Syntax des Inhaltes hängt vom Parameter DBMS ab.
ELEMENT change (description?, logparam*) ATTRIBUTE version string ignoreError bool type string dbms string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
version | string | - | - | Die Version, auf welche sich der Eintrag bezieht. |
ignoreError | bool | - | no | Wird verwendet, um der Funktion, welche die Aktualisierung durchführt, mittzuteilen, wie diese reagieren soll, falls dieser Schritt während der Aktualisierung der Datenbankstruktur einen Fehler verursacht. Für den Wert "yes" sollte die Aktualisierung der Datenbank fortgesetzt werden, selbst wenn dieser Schritt fehlschlägt. Für den Wert "no" sollte die Aktualisierung gestoppt und alle vorherigen Änderungen zurückgenommen werden. |
dbms | string | - | generic | Der Name des Ziel-DBMS. Der Wert "generic" bedeutet, dass die Definition für jedes DBMS zutreffend ist. Gewöhnlich wird das als Rückfalloption für DBMS verwendet, an welche Sie entweder beim Erstellen der Datenbankstruktur noch nicht gedacht haben, oder welche das fragliche Feature nicht unterstützen. |
type | string | - | default | Ein beliebiger Text, welcher den Typ der Änderung eindeutig identifiziert. |
Dies ist ein generisches Element zum Ergänzen von nutzerdefinierten Typen von Aktualisierungen. Eine Implementierung zur Ausführung dieses Updates muss es erlauben, für jeden angegebenen Typ eine Funktion oder Methode zu definieren, welche das Element behandelt. Dieser Funktion oder Methode müssen die LogParam-Elemente als Parameter übergeben werden, in der Reihenfolge ihrer Definition. Die Ausführung kann auf einen bestimmten DBMS beschränkt werden. Das Description-Element kann zu Dokumentationszwecken verwendet werden und beliebigen Text enthalten.
ELEMENT logparam (#PCDATA) ATTRIBUTE name string
Attribut | Typ | Pflicht | Default | Beschreibung |
---|---|---|---|---|
name | string | - | - | Name des Parameters |
Ein Parameter, welcher an die aufgerufene Funktion übergeben wird. Der PCDATA-Bereich enthält den Wert des Parameters. Optional kann ein Name vergeben werden. Es dürfen keine zwei Parameter mit dem gleichen Namen definiert werden.
Die Bezeichnung "SML" ist eine Abkürzung für "Simple Markup Language". Das SML-Format wurde zwischen 2001 und 2003 mit dem Ziel entwickelt, eine leicht verständliche und syntaktisch saubere Darstellung zu schaffen, welches von einer breiten Masse der Nutzer akzeptiert werden würde.
SML ist gleichermaßen verwandt mit "JSON" ("JavaScript Object Notation") und "XML" ("Extensible Markup Language"). Es ist semantisch gleich mächtig zu JSON. Dies heißt, alle Konstrukte, welche in JSON ausgedrückt werden können, können ebenso im SML-Format dargestellt werden und umgekehrt. Es ist dennoch wichtig zu betonen, dass SML unabhängig von JSON entwickelt wurde. Beide Dialekte haben keinerlei gemeinsame historische Schnittpunkte.
Vereinfacht ausgedrückt, verwendet SML eine Semantik, vergleichbar mit der von JSON und eine Syntax vergleichbar mit der von XML. Es verbindet somit die unter Nutzern weithin akzeptierte Tag-Darstellung mit einer intuitiven Semantik.
Aufgabe des Dateiformats ist es, nicht-rekursive Datenfelder in Form einer sequentiellen Datei zu repräsentieren. Diese Datenfelder können entweder numerisch oder assoziativ sein und beliebige skalare Werte, oder wiederum andere Datenfelder enthalten, welchen den gleichen Anforderungen genügen müssen. Referenzen sind nicht zugelassen. Objekte werden analog zu JSON dargestellt, indem ihre öffentlichen Objektvariablen in Form eines assoziativen Datenfeldes gespeichert werden. Enthaltene nicht skalare Werte werden rekursiv behandelt.
Zweck dieses Dateiformats ist es, Parameter zu speichern, um Komponenten des Frameworks zu initialisieren. Zweck ist es nicht, größere Datenmengen in diesem Format zu speichern. Insbesondere ist das SML-Format nicht konzipiert als Ersatz für XML.
Unendliche Rekursionen werden nicht erkannt.
Zur Begründung ist Folgendes zu sagen: Der Test, ob eine beliebige Struktur unendliche Rekursionen aufweist ist nicht trivial. Der übliche Ansatz ist eine Pfadprüfung. Dabei fällt jedoch jeweils ein Overhead von T = O(n) Schritten an, wobei n der Länge des Pfades entspricht. Der Beweis dieser unteren Schranke für die Laufzeit ist trivial. Um Overhead zu vermeiden könnte in Betracht gezogen werden, diese Prüfung nur alle x Verarbeitungsschritte durchzuführen, wobei für die positive, ganze Zahl x mit x > 1 ein geeigneter Wert gewählt werden sollte. Trotz dieser potentiellen Optimierung ist damit zu rechnen, dass sich für das gesamte Programm inklusive Pfadprüfung eine quadratische Laufzeit ergibt. Dies ist in für viele Anwendungen jedoch nicht akzeptabel. Aus Gründen der Performance wurde daher absichtlich darauf verzichtet.
An dieser Stelle möchte ich anmerken, dass der naive Ansatz, die Zahl der Elemente zu bestimmen und zu prüfen, ob die Zahl der Iterationen die Zahl der Elemente übersteigt, selbstverständlich nicht praktikabel ist. Um alle Elemente zu "zählen", müsste eine vollständige Traversion durchgeführt werden. Falls diese jedoch einen unendlich rekursiven Pfad enthalten sollte, so würde das Programm niemals terminieren und das Ergebnis wäre somit undefiniert.
Die Aufgabe Dateien für die Initialisierung, beziehungsweise Konfiguration eines Frameworks bereitzustellen, ist nicht ganz trivial. Weil das Framework eine Vielzahl von Plugins besitzen kann, deren Konfigurationsoptionen in den gleichen Dateien abgelegt werden sollen wie die restliche Konfiguration. Anzahl, Struktur, Typ und Benennung dieser Daten ist zur Entwurfszeit jedoch unbekannt. Eventuell sind die Plugins, mit denen das Framework arbeiten wird, zu diesem Zeitpunkt auch noch gar nicht geschrieben. Um unter diesen Umständen überhaupt im Voraus eine sinnvolle DTD oder Schema angeben zu können, ist es nur logisch sich auf natürliche Eigenschaften der Variablen zurückzuziehen. Stabile Eigenschaften wie beispielsweise der Datentyp einer Variablen sind geeignet um eine Struktur abzuleiten, welche vorhersagbar ist, weil sie durch stabile syntaktische Eigenschaften von PHP diktiert werden.
Weil PHP nicht streng typisiert ist und Referenzen, sowie Objekte per Definition kein Teil dieser Konfiguration sein dürfen, bleiben die Menge der skalaren Variablen und die Menge der Datenfelder. Dementsprechend werden analog zwei verschiedene Arten von Knoten definiert. Für die Darstellung skalarer Variablen soll der Tag "scalar" eingeführt werden. Dieser darf lediglich CDATA-Abschnitte enthalten – was gerade einem skalaren Kontext entspricht – jedoch keine weiteren Tags, respektive Elemente. Für die Darstellung von Datenfeldern soll der Tag "array" eingeführt werden. Dieser darf wiederum keine CDATA-Bereiche enthalten, sondern lediglich weitere Tags. Diese Tags repräsentieren die Elemente des Datenfelds. Weil XML ein eindeutiges Wurzelelement verlangt, wird zudem der Tag "root" eingeführt. Weitere Tags werden nicht benötigt.
Betrachten Sie das folgende Beispiel, welches zwei Datenfelder darstellt.
<?xml version="1.0" ?>
<!DOCTYPE example SYSTEM "example.dtd">
<root>
<array name="a">
<array name="0">
<scalar name="a"><![CDATA[wert]]></scalar>
<scalar name="b"><![CDATA[wert]]></scalar>
<scalar name="c"><![CDATA[wert]]></scalar>
</array>
<array name="1">
<scalar name="a"><![CDATA[wert]]></scalar>
<scalar name="c"><![CDATA[wert]]></scalar>
</array>
</array>
<array name="b">
<array name="0">
<scalar name="q"><![CDATA[wert]]></scalar>
<scalar name="r" />
<scalar name="s"><![CDATA[wert]]></scalar>
<scalar name="t"><![CDATA[wert]]></scalar>
</array>
</array>
</root>
An diesem Beispiel fallen einige Besonderheiten auf. Erstens ist das Element "root" völlig ohne semantische Bedeutung. Es existiert einzig und allein, weil die Syntax es erfordert.
Etwas künstlich wirken auch die leeren Tags. Sie sind zwar enthalten, aber es ist nicht ganz klar, wie diese in Bezug auf Variablen interpretiert werden sollen. PHP erfordert keine Definition von Variablen vor der ersten Verwendung. Eine Initialisierung einer zuvor nicht existierenden Variable, geschweige einer Konstante, mit "null" ist somit nicht wirklich sinnvoll. Zumal in einer Konfigurationsdatei ein null-Wert semantisch keinen Sinn machen wird. Daher soll per Konvention festgelegt werden, dass auf leere Tags komplett verzichtet werden sollte. Zugriffe auf leere oder nicht existierende Tags werden gemäß der in PHP üblichen Konventionen zu boolean "false" ausgewertet.
Weiterhin ist absehbar, dass diese Darstellung bei größeren Datenmengen unübersichtlich werden könnte. Betrachtet man beispielsweise den Fall, dass ein Datenfeld möglicherweise 50 oder mehr Einträge aufweist, welche zudem eventuell noch tief verschachtelt sind und große CDATA-Abschnitte mit mehreren Zeilenumbrüchen enthalten, dann ist anzunehmen, dass die Lesbarkeit beeinträchtigt wäre. Es wäre für die Lesbarkeit also von Vorteil, wenn aus einem End-Tag direkt ablesbar wäre, welches Element denn nun gerade geschlossen wurde.
Die gesonderte Kennzeichnung der CDATA-Abschnitte, könnte ebenfalls die Lesbarkeit beeinträchtigen, zumal sich der Sinn für den XML-unerfahrenen Laien nicht trivial erschließen muss. Zudem verlangen die zuvor getroffenen Festlegungen explizit, dass an dieser Position ohnehin gar nichts anderes als ein CDATA-Abschnitt folgen darf, weshalb eine Auszeichnung keinen echten Mehrwert bringt, sondern wiederum lediglich eine syntaktische Ursache hat. Es gibt einen seltenen Ausnahmefall, nämlich dass der CDATA-Abschnitt einen schließenden "scalar"-Tag enthält. Diese Fall kann jedoch auch mit Hilfe von Entities umgangen werden, sodass die Kennzeichnung insgesamt obsolete ist.
Abschließend soll die Schreibweise der Tags betrachtet werden. Beispielsweise die Bezeichnung "<array name="b">". Diese Schreibweise könnte auf Laien, überfrachtet und unnötig kompliziert wirken. Denn: dass es sich um ein Datenfeld handeln muss, wird bereits aus der Struktur des Elements deutlich, weil es nur ein einziges anderes Element gibt. Der Tag "scalar" kann aber aus rein syntaktischen Gründen an dieser Stelle gar nicht stehen, weil dieser keine Tags, sondern nur CDATA enthalten darf. Extra zu erwähnen, dass es sich um ein Datenfeld handelt ist somit im Grunde überflüssig. Das Attribut "name" ist allen Tags gemeinsam. Dies ergibt sich zwangsläufig aus syntaktischen Eigenschaften von PHP. Das Attribut entspricht also dem Bezeichner der Variable in PHP. Intuitiver wäre es statt er Bezeichnung "array" oder "scalar" den Bezeichner der Variablen als Tag zu benutzen. Analog gilt die gleiche Betrachtung für den Tag "scalar".
Berücksichtigt man alle diese Einwände so lässt sich folgende vereinfachte Darstellung gewinnen.
<a>
<0>
<a>wert</a>
<b>wert</b>
<c>wert</c>
</0>
<1>
<a>wert</a>
<c>wert</c>
</1>
</a>
<b>
<0>
<q>wert</q>
<s>wert</s>
<t>wert</t>
</0>
</b>
Auch ohne umfangreiche Erläuterung ist erkennbar, dass beide Varianten inhaltlich das Gleiche ausdrücken. Ebenso sollte vermutlich keine Diskussion darüber erforderlich sein, welche der beiden Schreibweisen intuitiver erfassbar, oder leichter lesbar wäre.
Aufgrund ihrer syntaktischen Eigenschaften ist diese Variante jedoch kein wohlgeformtes XML-Dokument mehr. Beispielsweise gibt es mehr als ein Wurzelelement und zudem ist "0" in XML kein gültiger Name für einen Tag. Es war somit notwendig eine andere Bezeichnung zu wählen. Diese Bezeichnung ist "SML" für "simple markup language", in Anlehnung an "XML" ("eXtensible markup language").
Gegenüber XML verlangt SML eine Reihe abweichender syntaktischer Eigenschaften. Zunächst ist zu erwähnen, dass die Kodierung einer Datei in UTF-8 oder UTF-16, wie beispielsweise bei XML üblich, leider in vielen Sprachen nach wie vor noch zu Problemen beim Lesen der Dateien führen kann. Zu diesen Sprachen zählen zum gegenwärtigen Zeitpunkt unter anderem Perl 5 und bedauerlicherweise PHP 4. Dies ist zwar ein Versäumnis der Entwickler und keine Eigenschaft von XML als solches, dennoch stellt es einen inakzeptablen Zustand dar, wenn es darum geht eine Anwendung zu initialisieren. Daher ist es sinnvoll für die Zwecke der Initialisierung des Frameworks von der Verwendung dieser Kodierungen abzusehen. Als Zeichensatz wird ISO Latin-1 verwendet. Zeichen, welche darin nicht enthalten sind, sollten durch geeignete Entitäten kodiert werden.
Abweichend von der XML-Syntax wird für SML nicht gefordert, dass das Dokument nur einen einzigen Tags als Wurzelelement enthalten darf. Sollte ein Dokument einen Wald aus mehreren Bäumen enthalten, so werden diese implizit als Kindelemente eines anonymen, virtuellen Wurzelelements enthalten.
Als weitere syntaktische Eigenschaft fordert das SML-Format, dass alle öffnenden Tags durch einen in gleicher Weise benannten schließenden Tag geschlossen werden müssen. Bei der Benennung der Tags kommt es nicht auf die Schreibweise an. Es wird nicht zwischen Groß- und Kleinschreibung unterschieden.
Weiterhin muss per Konvention nach jedem schließenden Tag zwingend ein Zeilenumbruch erscheinen. Vor einem öffnenden Tag dürfen per Konvention lediglich Whitespace-Zeichen eingefügt werden. Ein Tag kann entweder nur Textinhalt ("CData") oder weitere Tags enthalten, aber nicht beides gleichzeitig. Falls der Tag einen CDATA-Abschnitt enthält, müssen der Starttag und der Endtag auf der gleichen Zeile sein. Falls der Tag weitere Tags enthält, muss nach dem Starttag ein Zeilenumbruch erfolgen. Zeilenumbrüche in CDATA-Abschnitten können durch die Escapesequenz "\n" ausgedrückt werden.
Alle CDATA-Abschnitte außerhalb eines Tags oder Abschnitte welche nicht der Syntax entsprechen, werden als Kommentare behandelt und bei der Verarbeitung der Datei ignoriert. Eine besondere Markierung von CDATA-Abschnitten oder Kommentaren, wie in XML üblich, entfällt.
Die Verwendung der XML-typischen Schreibweise für leere Tags, beispielsweise "<br />" ist nicht gestattet (verwenden sie "<br></br>" stattdessen).
Abschließend soll gelten, dass auf die Verwendung von Attributen verzichtet werden soll.
Der Grund für diese recht restriktive Syntax wird deutlicher bei Betrachtung eines einfachen Beispiels.
Im Folgenden sollen Beispiele beschrieben werden, welche zeigen, auf welche Weise native Datentypen in PHP-Skripten durch das SML-Format darstellbar sind.
Darstellung in PHP-Code:
<?php
$a = 1;
$b = 'string';
$c = 12.5;
$d = true;
?>
äquivalente Darstellung in SML:
<a>1</a>
<b>string</b>
<c>12.5</c>
<d>true</d>
An dieser Stelle ist es wichtig eine syntaktische Einschränkungen von PHP zu verstehen. Eine PHP-Funktion kann nur einen einzelnen Rückgabewert besitzen. (Der Fall, dass der Funktion Parameter per Referenz übergeben werden, wird hier nicht betrachtet.) Eine PHP-Funktion welche den Inhalt des SML-Dokuments auswertet und als Rückgabewert liefert, ist daher gezwungen, die Inhalte in Form eines Arrays zu repräsentieren. Die Inhalte dieses Arrays können wiederum in Variablen innerhalb des Kontext des aufrufenden Programmfragments kopiert werden, wodurch der ursprüngliche Zustand wiederhergestellt wird.
Um ein zweites Beispiel zu nennen: Dokumente in JSO-Notation unterliegen den gleichen Einschränkungen.
Darstellung in PHP-Code:
<?php
$A = array();
$A[0] = 1;
$A[1] = 'string';
$A[2] = 12.5;
$A[1000] = true;
$B = array();
$B[0] = 2;
?>
äquivalente Darstellung in SML:
<A>
<0>1</0>
<1>string</1>
<2>12.5</2>
<1000>true</1000>
</A>
<B>
<0>2</0>
</B>
Darstellung in PHP-Code:
<?php
$SCREEN = array();
$SCREEN["width"] = 1024;
$SCREEN["height"] = 768;
$SCREEN["depth"] = "32-Bit";
?>
äquivalente Darstellung in SML:
<SCREEN>
<width>1024</width>
<height>768</height>
<depth>32-Bit</depth>
</SCREEN>
Darstellung in PHP-Code:
<?php
$A = array();
$A["a"] = 1;
$A["b"] = 2;
$A[0] = "drei";
$B = array();
$B[0] = true;
$B["a"] = 1000;
$B["b"] = array();
$B["b"][0] = 1;
$B["b"][1] = 2;
$B["b"]["a"] = 3;
?>
äquivalente Darstellung in SML:
<A>
<a>1</a>
<b>2</b>
<0>drei</0>
</A>
<B>
<a>1000</a>
<b>
<0>1</0>
<1>2</1>
<a>3</a>
</b>
</B>
Wie aus den obigen Beispielen ersichtlich, eignet sich das beschriebene Format gut um skalare Variablen und Datenfelder darzustellen, welche üblicherweise als Parameter für die Initialisierung des Frameworks in Frage kommen dürften. Die Angabe eines Typs ist nicht erforderlich, weil PHP nicht streng typisiert ist. Der Typ einer Variablen ist zur Laufzeit folglich dynamisch. Die einzige notwendige Unterscheidung findet zwischen skalaren Werten und Datenfeldern statt. Diese Unterscheidung ist trivialerweise anhand der Syntax möglich.
Zu dem für dieses Framework verwendeten SML-Dateiformat gibt es eine Anzahl populärer Alternativen. Der folgende Abschnitt wird einige dieser Alternativen vorstellen, vergleichen und die Ergebnisse diskutieren.
Im Folgenden sollen verschiedene Teilaspekte betrachtet werden:
Da nicht ausgeschlossen werden kann, dass eine Bearbeitung des Quelltextes der Dateien teilweise von Hand erfolgen muss, ist der Lesbarkeit des Quelltextes ein Kriterium, das beleuchtet werden soll. Die Syntax sollte im Idealfall intuitiv zu erfassen sein. Insbesondere ist dies wichtig, da zum gegenwärtigen Zeitpunkt nur für eine Untermenge der Gesamtheit der Konfigurationsmerkmale des Frameworks eine grafische Oberfläche bereitgestellt werden kann. In Anbetracht der Fülle an Optionen ist es darüber hinaus auch auf absehbare Zeit eher unwahrscheinlich, dass eine vollständige Abdeckung erreicht werden kann. Es stellt sich ohnehin die Frage, ob dies überhaupt wünschenswert wäre. Schließlich sollte auch berücksichtigen werden, dass es prinzipiell erfahrene Anwender gibt, welche bewusst und absichtlich auf die Funktionen einer "schwerfälligen" GUI verzichten, weil sie diese eher als Behinderung anstatt als Bereicherung empfinden.
Ein interessanter Faktor ist auch die Performance, da das Dateiformat einem eventuell zeitkritischen Zweck genügen soll, nämlich der Initialisierung des Frameworks. Begründet dadurch, dass die Dateien bei jedem Aufruf des Frameworks neu gelesen und dabei eventuell auch durch einen Parser untersucht werden müssen bevor ihre Informationen verfügbar sind, sollte dieser Vorgang mit möglichst geringen Kosten im Hinblick auf die Rechenzeit auskommen. Nicht immer ist ein sinnvoller Vergleich möglich, wo sich ein Vergleich jedoch anbietet sollte er durchgeführt werden.
Darüber hinaus sollten die Grenzen des jeweiligen Dateiformats beachtet werden. Wenn es Faktoren gibt, welche dazu führen können, dass ein Einsatz unter bestimmten Bedingungen nicht mehr sinnvoll ist, sollten diese genannt werden.
Die Portabilität der Dateien in andere Programmiersprachen ist eine der Stärken von XML. Parser für XML sind in den Funktionsumfang nahezu jeder modernen Skript- oder Programmiersprache integriert. Dies fällt jedoch für dieses Anwendungsgebiet – die Initialisierung des Frameworks – nicht ins Gewicht, da die für die Umsetzung des Frameworks gewählte Sprache ist PHP und Implementierungen des Frameworks in anderen Sprachen existieren zurzeit nicht.
Das aktuelle Werkzeug der Wahl zur Behandlung von XML, welches gleichermaßen für PHP 4 als auch PHP 5 verfügbar ist, ist zum gegenwärtigen Zeitpunkt der interne XML-Parser. Dieser XML-Parser besitzt allerdings eine Schwachstelle. Er ist lediglich zum Lesen von XML-Dateien verwendbar, nicht jedoch zum Schreiben. Eine Implementierung zum Erzeugen von XML-Dateien ist erst für PHP ab Version 5 als Standardkomponente enthalten.
Hinzu kommt, dass mithilfe des XML-Parsers ein assoziatives Datenfeld aus einer XML-Datei zu erstellen ähnlich viel Programmieraufwand benötigt, wie für das Schreiben eines Skripts für das Laden einer SML-Datei erforderlich gewesen ist. Allerdings ist dies mit dem Risiko verbunden, dass sich die Implementierung des XML-Parsers in einer späteren Veröffentlichung der Sprache möglicherweise verändert, auch wenn dies grundsätzlich unwahrscheinlich ist. Zudem gibt es keine sonstigen wesentlichen Vorteile dieser Implementierung, abgesehen von der allgemeinen Beliebtheit von XML als Dialekt.
Als weiteres Argument wäre die Performance zu beleuchten. Dies gestaltet sich jedoch alles andere als unproblematisch und die Ergebnisse sind nur unter Vorbehalt zu betrachten, da diese abhängig sind vom eingesetzten Werkzeug. Derer gibt es viele für das XML-Format, selbst wenn sich auf PHP als solches beschränkt wird.
Um einen Vergleich anstellen zu können, soll ein einfaches XML-Dokument geladen und in ein Datenfeld übertragen werden.
Zum Vergleich hier der Quelltext des verwendeten XML-Dokuments.
<?xml version="1.0"?>
<root>
<array name="channel">
<scalar name="title">Test</scalar>
<scalar name="link">about:blank</scalar>
<scalar name="description" />
<scalar name="language">de-de</scalar>
<array name="0">
<scalar name="title">Testeintrag 1</scalar>
<scalar name="pubDate">Do, 9 Jun 2005 13:23:18 +0200</scalar>
<scalar name="description"><![CDATA[Testeintrag]]></scalar>
<scalar name="link" />
<scalar name="author">Testautor</scalar>
</array>
<array name="1">
<scalar name="title">Testeintrag 2</scalar>
<scalar name="pubDate">Do, 9 Jun 2005 13:23:53 +0200</scalar>
<scalar name="description"><![CDATA[Testeintrag]]></scalar>
<scalar name="link" />
<scalar name="author">Testautor</scalar>
</array>
<array name="2">
<scalar name="title">Testeintrag 3</scalar>
<scalar name="pubDate">Do, 9 Jun 2005 13:24:18 +0200</scalar>
<scalar name="description"><![CDATA[Testeintrag]]></scalar>
<scalar name="link" />
<scalar name="author">Testautor</scalar>
</array>
<array name="3">
<scalar name="title">Linktest</scalar>
<scalar name="pubDate">Do, 9 Jun 2005 13:24:36 +0200</scalar>
<scalar name="description"><![CDATA[Testeintrag]]></scalar>
<scalar name="link">about:blank</scalar>
<scalar name="author">Testautor</scalar>
</array>
</array>
</root>
Anschließend das Gleiche im SML-Format.
<channel>
<title>Test</title>
<link>about:blank</link>
<language>de-de</language>
<0>
<title>Testeintrag 1</title>
<pubDate>Do, 9 Jun 2005 13:23:18 +0200</pubDate>
<description>Testeintrag</description>
<author>Testautor</author>
</0>
<1>
<title>Testeintrag 2</title>
<pubDate>Do, 9 Jun 2005 13:23:53 +0200</pubDate>
<description>Testeintrag</description>
<author>Testautor</author>
</1>
<2>
<title>Testeintrag 3</title>
<pubDate>Do, 9 Jun 2005 13:24:18 +0200</pubDate>
<description>Testeintrag</description>
<author>Testautor</author>
</2>
<3>
<title>Linktest</title>
<pubDate>Do, 9 Jun 2005 13:24:36 +0200</pubDate>
<description>Testeintrag</description>
<link>about:blank</link>
<author>Testautor</author>
</3>
</channel>
Zum Vergleich wird PHP 4 mit dem im Standard enthaltenen XML-Parser herangezogen. Dabei wird so vorgegangen, dass vor und nach jedem Parsen jeweils mithilfe des Befehls "microtime" eine Messung durchgeführt wird. Die Differenz zwischen beiden Werten wird in Millisekunden ausgegeben. Es kommt dabei nicht darauf an, wie viele Millisekunden die eine oder andere Technik schneller ist. Das objektiv zu beurteilen ist mit diesem Testverfahren selbstverständlich unmöglich, denn das Verfahren ist viel zu rudimentär um repräsentative Ergebnisse zu liefern.
Die Konfiguration des Testsystems kann in diesem Fall vernachlässigt werden, da lediglich die Größenordnung der Differenz zwischen beiden Techniken betrachtet werden soll.
Äußert problematisch für eine objektive Bewertung ist zudem der unglückliche Umstand, dass der XML-Parser zur Behandlung der Start-Tags, End-Tags und CDATA-Bereiche Einschübe aus handgeschriebenem PHP-Code benötigt. Es wäre somit denkbar, dass Effekte durch mehr oder minder performanten PHP-Code das Ergebnis der Messung verfälschen. Daher wird der XML-Parser sowohl einmal mit einer vergleichbaren Implementierung, als auch ein zweites Mal zum Vergleich ohne irgendeine Implementierung gemessen.
Ziel des Tests ist es nicht, ein Votum zu treffen für oder gegen den Einsatz des XML-Parsers. Vielmehr soll sich zeigen, ob es deutliche Unterschiede zwischen beiden Varianten gibt. Insbesondere, ob die SML-Variante um Größenordnungen langsamer als der XML-Parser ist. Dies könnte einen Hinweis darauf liefern, dass die gefundene Lösung möglicherweise aus Gründen schlechter Performance nicht für das Framework geeignet sein könnte.
Für diese recht bescheidene Aufgabenstellung sollte diese äußert einfache Testmethode trotz allem ausreichend genaue Ergebnisse liefern.
XML-Parser 1 | XML-Parser 2 | SML-Skript | Differenz SML zu XML 1 |
Differenz SML zu XML 2 |
---|---|---|---|---|
0,003685s | 0,001813s | 0,001626s | -0,001153s (31%) | -0,000187s (10%) |
0,003410s | 0,001666s | 0,001255s | -0,002155s (63%) | -0,000411s (24%) |
0,003367s | 0,001629s | 0,001312s | -0,002055s (61%) | -0,000317s (19%) |
0,003394s | 0,001614s | 0,001240s | -0,002154s (63%) | -0,000374s (23%) |
0,003381s | 0,001618s | 0,001228s | -0,002153s (63%) | -0,000390s (24%) |
0,003386s | 0,001613s | 0,001400s | -0,001986s (59%) | -0,000213s (13%) |
0,003387s | 0,001620s | 0,001296s | -0,002091s (61%) | -0,000324s (20%) |
0,003658s | 0,001617s | 0,001247s | -0,002411s (65%) | -0,000370s (22%) |
0,003678s | 0,001633s | 0,001454s | -0,002224s (60%) | -0,000179s (10%) |
0,003725s | 0,001613s | 0,001573s | -0,002152s (58%) | -0,000040s (2%) |
Vergleich der Performance zwischen XML-Parser und SML-Skript (Auszug)
1 XML-Parser bei Verwendung einer zum SML-Skript vergleichbaren Implementierung
2 XML-Parser im Leerlauf, ohne Verarbeitung der Eingabe
Betrachtet man den obigen, kurzen Auszug der Ergebnisse so fällt einerseits auf, dass der mit PHP-Code bestückte XML-Parser weniger performant agiert hat als das SML-Skript. Dies könnte jedoch wie bereits erwähnt auch eine Frage weniger performanter Programmierung sein. Betrachtet man jedoch Spalte 2 ("XML-Parser 2") im Vergleich zu Spalte 3 ("SML-Skript") so sieht man, dass auch in diesem Fall die SML-Variante nah bei den Werten des XML-Parsers liegt. Dies ist insbesondere bemerkenswert, da der XML-Parser in diesem Fall gar kein Ergebnis produzierte, da keine Implementierung zur Bearbeitung des Inhalts angegeben wurde. Aus diesem Grunde kann das Argument, dass eine ungünstig gewählte Implementierung den XML-Parser verlangsamt haben könnte, nicht mehr aufrecht erhalten werden.
Dieser Test lieferte folglich keinen Hinweis darauf, dass die Leistungsfähigkeit der Implementierung einen negativen Effekt auf die Performance der gesamten Anwendung ausüben könnte.
Syntaktisch gesehen unterscheidet sich die Benutzung von SimpleXML für den Entwickler nur unwesentlich von der Verwendung des SML-Skripts, wie der nachfolgende Quellcodeauszug verdeutlicht.
<?php $sml = SML::getFile("test.config"); $xml = simplexml_load_file("test.xml"); ?>
Der einzige offensichtliche Unterschied liegt im Typ des Rückgabewerts.
Während die SML-Variante ein assoziatives Datenfeld als Ergebnis
liefert, gibt SimpleXML ein Objekt vom Typ "SimpleXMLElement" zurück.
Man mag geteilter Auffassung darüber sein, welche Variante die
glücklichere Wahl ist.
Gegen SimpleXML spricht, dass es die Namen von Tags und Attributen auf Namen von Objekten und der Eigenschaften in PHP ab. Das ist problematisch, weil diese in PHP und XML jeweils unterschiedliche Zeichen enthalten dürfen. Zum Beispiel betrifft dies das Zeichen '-', welches in PHP nicht für die Benennung von Variablen verwendet werden darf. Folglich kann man zum Zeitpunkt der Erstellung dieses Dokuments über SimpleXML auf einen Tag namens <foo-bar> nur sehr umständlich zugreifen.
Initialisierungsdateien, häufig abgekürzt mit der Dateiendung "ini", sind ihrerseits eine geeignete Alternative, sofern keine Abbildung von komplexen Strukturen erforderlich ist. Die Darstellung von Schlüsseln, insbesondere bei tief verschachtelten Informationen, kann jedoch im Einzelfall unübersichtlich werden. Das Format bietet syntaktisch einen einfachen Aufbau. Allerdings müssen dem Format einige Abstriche gegenüber XML zugestanden werden. Es fehlt zum Beispiel die typische Schreibweise in Form von Tags, welche derzeit populär ist. Das Erstellen einer DTD oder einer vergleichbaren Datei, welche die Struktur des Dateiformats beschreibt, ist sowohl praktisch als auch aus theoretischen Überlegungen heraus nicht möglich. Dies ist jedoch kein Nachteil. Bedenkt man, dass die vordergründige Aufgabe dieses Dateiformats darin besteht, eine Abbildung von beliebig strukturierten assoziativen Datenfeldern aus einer Skript- oder Programmiersprache heraus auf ein Dateiformat zu realisieren, wird deutlich, dass die Vorgabe einer statischen Struktur nicht sinnvoll ist. Ideal wäre eine Kombination, welche die Vorteile beider Formate in sich vereint.
Der folgende Quellcodeauszug zeigt ein Beispiel für eine Initialisierungsdatei.
[STORE\0]
type=book
author=Dr. A Beispiel
[STORE\0\TITLE]
main=Protomaterie
subtitle=Alpha et Omega
[STORE\1]
type=cd
author=Barbara Sänger
[STORE\1\TITLE]
main=Best-Of
Eine weitere Alternative ist die Verwendung von JSON. Im Folgenden ein Beispiel:
"STORE" : {
"0" : {
"type" : "book",
"author" : "Dr. A Beispiel",
"TITLE" : {
"main" : "Protomaterie",
"subtitle" : "Alpha et Omega"
}
},
"1" : {
"type" : "cd",
"author" : "Barbara Sänger",
"TITLE" : {
"main" : "Best-Of"
}
}
}
PHP bietet die Möglichkeit, ähnlich wie beispielsweise Java, mit den Befehlen "serialize" und "unserialize" Variablen zu serialisieren und wiederherzustellen.
Der folgende Quellcodeauszug zeigt ein Beispiel.
a:1:{s:7:"CHANNEL";a:7:{s:5:"TITLE";s:4:"Test";s:4:"LINK";s:11:"about :blank";s:8:"LANGUAGE";s:5:"de-de";i:0;a:4:{s:5:"TITLE";s:13:"Testein trag 1";s:7:"PUBDATE";s:29:"Do, 9 Jun 2005 13:23:18 +0200";s:11:"DESC RIPTION";s:11:"Testeintrag";s:6:"AUTHOR";s:9:"Testautor";}i:1;a:4:{s: 5:"TITLE";s:13:"Testeintrag 2";s:7:"PUBDATE";s:29:"Do, 9 Jun 2005 13: 23:53 +0200";s:11:"DESCRIPTION";s:11:"Testeintrag";s:6:"AUTHOR";s:9:" Testautor";}i:2;a:4:{s:5:"TITLE";s:13:"Testeintrag 3";s:7:"PUBDATE";s :29:"Do, 9 Jun 2005 13:24:18 +0200";s:11:"DESCRIPTION";s:11:"Testeint rag";s:6:"AUTHOR";s:9:"Testautor";}i:3;a:5:{s:5:"TITLE";s:8:"Linktest ";s:7:"PUBDATE";s:29:"Do, 9 Jun 2005 13:24:36 +0200";s:11:"DESCRIPTIO N";s:11:"Testeintrag";s:4:"LINK";s:11:"about:blank";s:6:"AUTHOR";s:9: "Testautor";}}}
Diese Lösung ist ohne Zweifel sehr performant. Der Befehl "unserialize" arbeitet mit dieser Eingabe noch einmal um den Faktor 2 schneller als SimpleXML. Problematisch ist jedoch die Lesbarkeit des erzeugten Datenstroms. Für händische Eingriffe ist diese Darstellung offensichtlich denkbar ungeeignet. Da eine gute Lesbarkeit für das Framework jedoch unabdingbar ist, wurde von einer Realisierung in dieser Form bis auf Weiteres abgesehen.
weiterführende Literatur
Unerwünschte Werbung in E-Mails, Foren oder Gästebüchern sind ein aktuelles Thema. In diesem Abschnitt wird erläutert, was man darunter versteht und es werden einige Methoden erläutert, mit denen Dritte "Spamming" oder "Flooding" betreiben. Anschließend wird gezeigt, auf welche Weise in diesem Framework versucht wird, diesen Bedrohungen zu begegnen.
Zwischen "Spam" und "Floods" gibt es trotz oberflächlicher Ähnlichkeiten einen feinen Unterschied, welcher im Folgenden dargelegt wird.
Unter "Spam" versteht man die mehrmalige, unaufgeforderte Übermittlung von medialen Inhalten an eine Person oder eine Gruppe von Personen. Beispielsweise das unaufgeforderte Versenden von E-Mails mit Werbeinhalten an Dritte. Aber auch massenhafte, unaufgeforderte Anrufe sind eine Form von "Spam". Der Versand von Spam ist in vielen Ländern (darunter Europa und die USA) illegal und wird strafrechtlich verfolgt.
Die Webseite "spamhaus.org" definiert "Spam" wie folgt.
The word " Spam " as applied to Email means Unsolicited Bulk Email ("UBE").
A message is Spam only if it is both Unsolicited and Bulk.
Unter " Flooding " versteht man das mutwillige, unaufgeforderte "überfluten" eines Mediums mit Inhalten. Floods zielen darauf ab, den normalen Betrieb eines Mediums zu stören. Beispielsweise das massenhafte Veröffentlichen sinnfreier Texte in einem öffentlichen Forum. Aber auch eine Person, welche eine öffentliche Veranstaltung durch permanente Zwischenrufe stört, betreibt dem Grunde nach eine Form von Flooding. Flooding kann in einigen Fällen illegal sein. Beispielsweise dann, wenn ein wirtschaftlicher Schaden entsteht.
In der Regel wird "Spam" mit der Intention erstellt, Werbebotschaften zu vermitteln. Wohingegen "Floods" meist eher eine Form von Vandalismus darstellen.
Ein zunehmendes Problem stellt der Spam in Foren und Gästebüchern dar. Aber auch Blogs und Wikis sind betroffen. Meist werden solche Einträge zwar schnell aufgespürt und wieder entfernt, aber die Beseitigung unerwünschter Einträge dieser Art kostet Zeit und Geld. Im Folgenden Abschnitt wird beschrieben, auf welche Weise ein Angreifer dabei vorgehen könnte und es werden Mittel und Wege aufgezeigt, dem angemessen zu begegnen.
Der Angreifer geht dabei wie folgt vor. Zunächst sucht er ein anfälliges Skript eines Gästebuches oder Forums, welches eine ausreichend große Verbreitung im Internet besitzt. Er untersucht die Formulare zum Erstellen neuer Einträge und notiert die Bezeichnungen der erforderlichen Formularfelder. Der Angreifer späht bestimmte typische Texte innerhalb der Anwendung aus. Unter Verwendung dieser Texte als Suchbegriffe, findet er bei Suchdiensten Webseiten, auf denen das Skript installiert ist.
Der Angreifer erstellt eine Liste der URLs dieser Seiten, welche er in einer Datei ablegt. Mit Hilfe eines kurzen Programms trägt er, beispielsweise über einen anonymen Proxyserver, asynchron in einer einfachen Schleife Werbebotschaften in alle Formulare der Liste ein.
Wenn der Angreifer Glück hat, indexieren obendrein Suchmaschinen wie Google diese Seiten bevor der zuständige Administrator die Werbung entfernt. Auf diese Weise erhöhen in die Werbebotschaft eingebettete Hyperlinks obendrein den PageRank der so beworbenen Internetangebote, was dazu führen kann, dass diese bei Suchmaschinen leichter auf den vorderen Plätzen landen.
Es gibt mehrere Methoden solche Angriffe abzuwehren.
Die einfachste Möglichkeit besteht darin, schlicht und ergreifend die URL zu ändern. Üblicherweise arbeiten die Skripte der meisten Angreifer asynchron. Es fällt dem Angreifer somit in der Regel nicht sofort auf, wenn eine Webseite nicht mehr erreichbar ist. Es ist davon auszugehen, dass der Angreifer um die URL zu korrigieren entweder auf das Update der Suchmaschine wartet, was durchaus 8 Wochen dauern kann, oder die Webseite selbst erneut besuchen und den neuen Link von Hand extrahieren muss. In beiden Fällen sollte das Opfer vorübergehend Ruhe vor dem Angreifer haben.
Für das Framework ist das Ändern der URL ohne Schwierigkeiten möglich. Das ist deshalb so einfach, weil das Framework beliebig viele durch eine ID-Kennung identifizierte Instanzen der installierten Anwendungen beziehungsweise Plugins in Form von "Konfigurationsprofilen" verwalten kann. Welche Profile aktiv sind und welche nicht, erschließt sich jedoch nur für den Webmaster selbst und nicht für den außenstehenden Nutzer.
Um die URL einer Anwendung zu ändern muss folglich lediglich das betroffene Profil umbenannt und neu verlinkt werden. Dies ist eine Frage von wenigen Minuten. Der positive Nebeneffekt besteht darin, dass der Angreifer selbst bei synchroner Übertragung, oder bei Prüfung der URL über ein automatisches Programm keinen Fehler 404 (Seite nicht gefunden) vom Server erhält. Selbst bei einer manuellen Prüfung bemerkt er durch einen direkten Aufruf der URL nicht, dass er ein inaktives Profil vor sich hat. Er wird je nach Konfiguration des Frameworks weiterhin Formulare aufrufen und (sofern das Profil nicht schreibgeschützt ist) Beiträge schreiben können.
Aus persönlicher Erfahrung kann ich berichten, dass sich Angreifer auf diese einfache Weise leicht monatelang in die Irre führen lassen, ohne ihren Fehler zu bemerken.
Eine weitere Maßnahme ist das Sperren von IPs oder IP-Blöcken. Das ist vor allem dann hilfreich, wenn der Angreifer stets die gleichen Proxyserver für seine Angriffe verwendet. Leider ist dies nicht häufig der Fall. Nichtsdestotrotz wurde diese Möglichkeit für das Framework berücksichtigt und eine entsprechende optionale Funktion eingebaut. Diese Funktion kann zudem auch dazu verwendet werden, bei Anwendungen in einem lokalen Netzwerk mit Zugang zum Internet den Zugriff auf die Anwendung auf das lokale Netzwerk zu beschränken und Zugriffe aus dem Internet zu untersagen.
Um von vorn herein zu verhindern, dass ein Angreifer mit einem automatischen Programm Einträge verfassen kann, gibt es die Möglichkeit in potentiell gefährdete Formulare Grafiken mit kombinierten Zahlen- und Buchstaben-Codes einzubauen. Um einen Eintrag schreiben zu können, muss der Besucher den eingeblendeten Code abtippen. Was für einen menschlichen Betrachter eine leichte Übung ist, gestaltet sich für ein automatisches Programm deutlich schwieriger.
Die Probleme welche sich für den Angreifer daraus ergeben sind vielfältig. Sein Programm muss zunächst erst einmal den aktuellen Code vom Server holen – selbst wenn es gelingt den Code zu extrahieren kostet dies in jedem Fall Zeit. Eine asynchrone Kommunikation ist daher nicht mehr möglich: die Anfrage muss gesendet und der Code muss empfangen werden. Dadurch besteht aber auch das Risiko, dass das Programm möglicherweise durch einen langsamen oder absichtlich modifizierten Server verlangsamt wird. Außerdem ist es mit deutlich größerem programmiertechnischen Aufwand verbunden.
Es ist davon auszugehen, dass ein Angreifer aus den zuvor genannten Gründen eine so geschütztes Webanwendung meiden wird.
Das Framework implementiert eine solche Codeabfrage. Die Standardbibliothek hält zu diesem Zweck die Aktionen "security_get_image" und "security_check_image" bereit, welche mit Hilfe der PHP GD-Bibliothek eine Grafik im PNG-Format erzeugen können und eine interne Codetabelle zum Vergleich der vom Nutzer eingegebenen Daten verwalten. Diese Tabelle wird durch eine ".htaccess" -Datei vor öffentlichen Zugriffen geschützt und in regelmäßigen Zeitabständen automatisch erneuert.
Flooding kann sowohl unbeabsichtigt als auch beabsichtigt sein.
Unbeabsichtigt kann dies beispielsweise dann leicht geschehen, wenn der Server vorübergehend stark belastet ist. In diesem Fall kann es passieren, dass ein einzelner Nutzer, der gerade einen Schreibzugriff auf die Datenbank in Auftrag gegeben hat, ungewohnt lange auf die Antwort des Servers warten muss. Aus Ungeduld kann es vorkommen, dass der Nutzer die Refresh-Funktion des Browser benutzt und somit die Daten ein zweites Mal an den Server sendet, was dazu führt, dass unbeabsichtigt zwei identische Einträge erstellt werden. Selbst wenn die Webseite selbst nur wenig besucht ist, kann dies dennoch recht häufig vorkommen, wenn die Webseite auf einem "shared server" gespeichert ist. Das heißt: wenn sich die Webseite, auf welcher das Framework installiert ist, einen Host mit anderen Kunden teilt. Es ist nicht unüblich, dass sich je nach Preiskategorie und Anbieter ohne Weiteres 1000 oder sogar 10000 verschiedene Kunden den gleichen Server und damit die gleichen Ressourcen teilen müssen.
Beabsichtigtes Flooding ist meist eine Form von "Vandalismus". Ziele des Angreifers ist es, die normale Nutzung der Seite zu stören beziehungsweise zu erschweren.
Sowohl beabsichtigtes als auch unbeabsichtigtes Flooding kann durch automatisierte Maßnahmen vermindert werden.
Es sollen zwei Methoden betrachtet werden, mit denen Nutzer den Betrieb der Anwendung versuchen könnten zu stören. Erstens: durch die Reihung überlanger Zeichenketten ohne Zeilenumbruch, Reihung einer überlangen Kette von Zeilenumbrüchen, überlangen Texten allgemein, oder übergroßer Grafiken, kann das Layout der Anwendung gestört werden. Dies bewirkt eventuell, dass Teile des grafischen Layouts nicht mehr so dargestellt werden, wie vom Entwickler beabsichtigt. Außerdem könnte es dazu führen, dass andere Nutzer umständlich scrollen müssen, weil die Darstellung anderer Beiträge dadurch beeinträchtigt wird.
Die zweite Methode ist das massenhafte Absetzen von irrelevanten Beiträgen. Dadurch wird es anderen Nutzern erschwert, wichtige Nachrichten zu erkennen und deren Inhalte zu nutzen. Der Angreifer sendet dazu mehrere identische, oder inhaltlich ähnliche Beiträge nacheinander an den Server.
Für die zweite Methode sieht das Framework folgende Lösung vor. Wenn zwei Beiträge nacheinander zur Speicherung vorgesehen werden, wird überprüft ob die Beiträge abgesehen vom Zeitindex den gleichen Inhalt haben. Ist dem so, dann wird der zweite Eintrag nicht gespeichert. Dies verhindert insbesondere unabsichtliches Flooding des Mediums, erschwert jedoch auch eventuelle Angriffe.
Zusätzlich gibt es eine Option, welche es erlaubt festzulegen, wie viele Einträge ein Nutzer prinzipiell nacheinander schreiben darf. Der Nutzer wird anhand der IP identifiziert. Ist die Option gesetzt und schreibt der Nutzer nacheinander mehr Einträge als vorgesehen, ohne dass ein anderer Nutzer in der Zwischenzeit auf einen der Beiträge geantwortet hat, dann wird dem Nutzer das Speichern weiterer Beiträge verweigert.
Für die Abwendung der ersten Methode sorgt eine Reihe von Filtern. Diese Filter beschränken die Textlänge, begrenzen die Größe für die Darstellung von Grafiken auf Maximalwerte, entfernen auffällige Wiederholungen und erzeugen zwangsweise Zeilenumbrüche, wenn eine Zeichenkette von mehr als 80 aufeinander folgenden Zeichen ohne Vorkommen eines Whitespace-Zeichen gefunden wird.
Diese Methoden erschweren einem Angreifer die Störung des normalen Betriebs, können aber dies nicht grundsätzlich verhindern. Dies wäre auch nicht unbedingt sinnvoll. Dies liegt an einem bekannten Dilemma. Verengt man den Trefferbereich der Filter, dann reduziert sich die Zahl der Falschmeldungen ("false-positives") von Einträgen, welche als Flood-Versuch erkannt werden, aber gar keine sind. Gleichzeitig schlüpfen jedoch auch eine höhere Anzahl echter Angriffe durch das Netz der Filter. Umgekehrt: erweitert man den Trefferbereich der Filter, fängt man mehr Angriffe ab. Allerdings erhöht sich auch die Zahl der "false-positives" dementsprechend. Im Endeffekt wird man somit stets einen "Trade-off" zwischen ausreichender Sicherheit und ausreichender Vermeidung von Falschmeldungen suchen.
weiterführende Literatur
Um die Sicherheit von Passwörtern zu erhöhen ist es sinnvoll diese zu verschlüsseln. Einwegverschlüsselungsverfahren [I] sind dazu gut geeignet. In diesem Abschnitt werden zwei der wichtigsten Vertreter beschrieben. In PHP sind diese über die Funktionen "md5()" beziehungsweise "crypt()" implementiert.
Das DES-Verfahren [II] war viele Jahre lang das Standard-Verschlüsselungsverfahren in den Vereinigten Staaten. Mit der Steigerung der Rechenleistung, welche in den letzten Jahren zu beobachten war, gilt das einfache DES-Verfahren inzwischen jedoch nicht mehr als sicher. Als sichere Modifikation gilt die dreifach Verschlüsselungsvariante "Triple-DES". Als Nachfolgeverfahren für DES wurde vom US-amerikanischen National Institute of Standards das so genannte RIJNDAEL-Verfahren AES [III] gewählt.
DES ist ein Verfahren welches auf der Binärdarstellung des Klartextes arbeitet. Es erzeugt zunächst eine initiale Permutation dieser Binärdarstellung. Anschließend wird eine Blockchiffre zur Verschlüsselung angewendet. Das DES-Verfahren ist eine Feistel-Chiffre. Feistel-Chiffren wenden mehrmals nacheinander eine interne Blockchiffre auf Teile der Nachricht an um eine Folge von Rundenschlüsseln zu erzeugen.
Für die Sicherheit von Feistel-Chiffren ist die Sicherheit der verwendeten internen Blockchiffre von entscheidender Bedeutung. Zurzeit wird DES immer noch als sicher genug für die meisten Alltagsanwendungen betrachtet und das Verfahren wird in vielen Umgebungen weiterhin verwendet. Beispielsweise findet DES Anwendung auf Unix-Systemen zur Authentifizierung von Nutzern.
Der MD5-Algorithmus [IV] gehört zur Gruppe der Hashverfahren. Wichtig für die Sicherheit eines Hashverfahrens ist die Eigenschaft der Kollisionsfreiheit. Eine Kollision besteht immer dann, wenn für zwei verschiedene Klartexte der gleiche Chiffretext erzeugt wird. Falls eine Kollision gefunden wird, so ist es möglich mit Hilfe geeigneter Verfahren den Klartext zu berechnen. Es ist bekannt, dass MD5 nicht kollisionsfrei ist. Jedoch ist unbekannt, ob es überhaupt irgendeine Kompressionsfunktion gibt, welche gar keine Kollisionen aufweist. Daher gilt es für die Praxis als ausreichend, wenn es hinreichend schwierig ist eine Kollision zu finden. Derartige Verfahren werden als "kollisionsresistent" bezeichnet. Ebenso wichtig ist die Geschwindigkeit des Algorithmus, denn die Verschlüsselung selbst sollte – um für die Authentifizierung geeignet zu sein – möglichst effizient arbeiten.
Name des Verfahrens | Blocklänge in Bit | Geschwindigkeit in Prozent |
---|---|---|
MD4 | 128 | 100 |
MD5 | 128 | 68 |
RIPEMD-128 | 128 | 39 |
RIPEMD-160 | 160 | 24 |
Vergleich der Performance verschiedener Authentifizierungsverfahren
Die Sicherheit von MD5 ist inzwischen jedoch am Wanken [V]. Der Heise-Verlag berichtete zunächst Anfang 2005 darüber, dass es Forschern offensichtlich gelungen ist ein schnelleres Verfahren zur Berechnung von MD5-Hashs zu finden, [VI] wodurch das Auffinden von Kollisionen erleichtert würde. Kurze Zeit später, erschien die Meldung, dass es gelungen sei, unterschiedliche Zertifikate mit gleichem MD5-Hash [VII] zu erzeugen. Nur etwas mehr als ein halbes Jahr danach zeigte sich die vorläufige Spitze der Entwicklung [VIII], als eine Firma erstmals offiziell gegen Bezahlung die Dienstleistung anbot, MD5 und SHA1 Hashes mithilfe im Voraus berechneter Tabellen zu knacken, solange das Honorar stimmt. Es ist somit nur eine Frage der Zeit, wann das MD5-Verfahren für sensible Anwendungen nicht mehr genügend Sicherheit bieten wird.
Auch der eigentlich als sicherer geltende Algorithmus SHA-1 [IX], der mit einer Bitlänge von 160-Bit im Gegensatz zu MD5 mit 128-Bit aufwartet, ist jedoch bereits gebrochen. Wie Schneier berichtete [X], ist es einer Gruppe chinesischer Kryptoanalytiker (Xiaoyun Wang, Yiqun Lisa Yin, Hongbo Yu) von der Universität Shandong gelungen, eine Kollision in SHA-0 beziehungsweise SHA-1 zu finden. Für SHA-0 in 2 39 Operationsschritten, sowie für SHA-1 in 2 69 Schritten. Deutlich schneller also als der Brute-Force Ansatz mit etwa 2 80 erforderlichen Operationsschritten.
Das Framework verwendet ebenfalls MD5 zur Verschlüsselung von Passwörtern. Zusätzlich wird SHA-1 zum Erzeugen eindeutiger Session-Ids verwendet. Eine Umstellung der Passwortverschlüsselung von MD5 auf SHA-1 wird zu gegebener Zeit erfolgen.
weiterführende Literatur
Thomas Meyer, www.yanaframework.net