2008 | RE-Design - Enrico Reinsdorf - Part 2

Schon seid vielen Jahren benutzte ich diese Klasse. Immer wenn ich ein kleines Template-System brauche setze ich auf diese Klasse. Die Funktionsweise meiner Klasse ist dabei recht einfach.

Als erstes wird im Konstruktor festgelegt wo die Vorlagen zu finden sind, dazu wird ihn der Pfad mit übergeben. Zusätzlich wird die „value“-Eigenschaft mit einem leeren Array vorbereitet.

  1. public function __construct( $path )
  2. {
  3. $this->path = $path.‘/’;
  4. $this->values = array();
  5. }

Um aber auch eine konkrete Vorlage zu laden, gibt es in der „Template“-Klasse die „load()“-Methode. Ihr wird der Dateiname übergeben. Die geladene Datei wird als String in die „source“-Eigenschaft abgelegt. Zusätzlich wird die „reload()“-Methode aufgerufen.

  1. public function load( $file )

  2. {
  3. $this->source = file_get_contents( $this->path.$file );
  4. $this->reload();
  5. }

Sie kopiert den geladene String in die „template“-Eigenschaft. So muss nicht beim wiederholten Aufrufen der gleichen Vorlage immer wieder erst die Datei von der Festplatte geladen werden.

  1. public function reload()
  2. {
  3. $this->template = $this->source;
  4. }

Über die „set()“-Methode werden die Werte mit ihren Schlüsselworten in die Klasse geladen. Dabei werden 2 Parameter erwartet: der Schlüssel mit folgender Schreibweise „##SCHLÜSSELNAME##“ (Name in Großbuchstaben) und optional ein Wert.

  1. public function set( $key, $value=)
  2. {
  3. $this->values[$key] = $value;
  4. }

Neben der „set()“-Methode gibt es natürlich auch die „get()“-Methode. Sie hat als Aufgabe aus dem Template einen brauchbare Quellcode für den Browser zu generieren. Dabei prüft sie als erstes ob überhaupt das Template schon geladen wurde. Danach ruft sie die „parse()“-Methode auf, um das Template mit den Werten zu verarbeiten. Falls der Methode über der „sourcecode“-Parameter der statische Wert Template::DISPLAY_CODE mitgegeben wurde, wird die Ausgabe in lesbaren HTML-Code konvertiert.

  1. public function get( $sourcecode=true )
  2. {
  3. if( $this->source==null || $this->source==)
  4. {
  5. return null;
  6. }
  7. $this->parse();
  8. if( !$sourcecode )
  9. {
  10. $out = ‘<pre>’;
  11. $out .= htmlentities( $this->template );
  12. $out .= ‘</prev>’;
  13. }
  14. else
  15. {
  16. $out = $this->template;
  17. }
  18. return $out;
  19. }

Die „parse()“-Methode hat nun die Aufgabe die Schlüsselworte innerhalb der Vorlage durch die Werte innerhalb der „values“-Eigenschaft zu ersetzen. Dabei prüft sie als erstes ob überhaupt das Template schon geladen ist. Danach ersetzt sie alle Werte. Zum Schluss werden noch alle nicht ersetzten Schlüsselworte in der Vorlage gelöscht, um unschöne Darstellungen zu vermeiden.

  1. private function parse()
  2. {
  3. if( $this->source == null || $this->source==)
  4. {
  5. die(‘TPL-Error: file not loaded!’);
  6. }
  7. foreach ( $this->values as $key => $value )
  8. {
  9. $this->template = str_replace( $key, $value, $this->template );
  10. }
  11. $this->template = ereg_replace( ‘##[A-Za-z0-9_]+##’, , $this->template);
  12. }

Als letzte Methode innerhalb der „Template“-Klasse gibt es noch die „write()“-Methode. Sie macht im Grunde genau das was die „get()“-Methode auch macht, nur gibt sie das Ergebnis direkt an den Browser weiter.

  1. public function write( $sourcecode=true )
  2. {
  3. echo $this->get( $sourcecode );
  4. }

Wie schon eingangs erklärt, ist diese Klasse eine meiner ersten Klassen die ich konstant in meinen Projekten einsetze. Die Verwendung ist dabei sehr einfach. Als erstes erstellt man eine Vorlagendatei mit folgenden exemplarischen Quellcode:

  1. <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
  2. <html xmlns=“http://www.w3.org/1999/xhtml”>
  3. <head>
  4. <meta http-equiv=“Content-Type” content=“text/html; charset=utf-8″ />
  5. <title>##TITLEBAR##</title>
  6. </head>
  7. <body lang=“de”>
  8. <div id=“page”>
  9. <div id=“branding”>
  10. <h1>##WEBSITETITLE##</h1>
  11. <h2>##TAGLINE##</h2>
  12. </div>
  13. <div id=“main”>
  14. <div id=“content”>
  15. ##CONTENT##
  16. </div>
  17. <div id=“sidebar”>
  18. ##SIDEBAR##
  19. </div>
  20. </div>
  21. <div id=“copyright”>
  22. <p>&copy; 2008 &ndash; <a href=“http://www.re-design.de”>RE-Design</a></p>
  23. </div>
  24. </div>
  25. </body>
  26. </html>

Um diese Vorlage verwenden zu können muss man in PHP nur folgendes schreiben:

  1. <?php

  2. include_once ‘core/Template.php’;
  3. $tpl = new Template(‘./templates/layouts’);
  4. $tpl->load(‘index.tpl.html’);
  5. $tpl->set(‘##TITLEBAR##’, ‘RE-Design - Beispiel-Template-Code’);
  6. $tpl->set(‘##WEBSITETITLE##’, ‘RE-Design’);
  7. $tpl->set(‘##TAGLINE##’, ‘Template-Klassen-Beispiel’);
  8. $tpl->set(‘##CONTENT##’, ‘<p>Lorem ipsum dolor sit amet, … et netus et malesuada fames ac turpis egestas.</p>’);
  9. $tpl->set(‘##SIDEBAR##’, ‘<div class=”box”><h2>Autor</h2><p>Enrico Reinsdorf</p></div>’);
  10. echo $tpl->get(Template::DISPLAY_HTML);
  11. ?>

Downloads

Dies wird heute ein sehr kurzer Beitrag, denn ich habe nicht wirklich eine eigene „Database“-Klasse geschrieben. Vielmehr habe ich auf die „DB“-Klasse des PEAR-Frameworks zurückgegriffen, da dieses Framework mittlerweile in fast jeder installiert hat.

  1. require_once (‘DB.php’);
  2. class Database extends DB
  3. {
  4. }

Wichtig aus dieser Klasse ist einmal die „connect()“-Methode, die als ersten Parameter die Verbindungsangaben für die Datenbank als String erfordert. Der Rückgabewert dieser Methode ist dann das Datenbank-Objekt.

Mit diesem Objekt können dann alle SQL-Anfragen abgewickelt werden. Hier kein kleines Beispiel :

  1. $query = ‘SELECT * FROM page’;
  2. $res =& $db->query($query);
  3. if (PEAR::isError($res)) {
  4. die($res->getMessage());
  5. }
  6. while ($res->fetchInto($page))
  7. {
  8. array_push($pages, $page);
  9. }

Downloads

Jedes System sollte eine einfache Möglichkeit besitzen konfiguriert zu werden. In den meisten Fällen gibt es eine Konfigurationsdatei – so auch bei mir. Allerdings habe ich mir überlegt, die Konfiguration nicht in eine PHP-Datei einzubetten, sondern in eine INI-Datei. So ist es schnell möglich diese einfache Textdatei anzupassen.

Allerdings hat die Vorgehensweise auch Nachteile. Da diese besondere Datei nicht vor fremden Augen geschützt ist, kann sie jeder leicht einsehen, der die URL kennt. Um das Ausliefern der Datei von Apache zu verhindern, habe ich die „.htaccess“-Datei angepasst.

  1. <Files ~ “.(ini)$”>
  2. Order allow,deny
  3. Deny from all
  4. </Files>

Kommen wir jetzt zur Konfigurationsdatei. Sie ist in 3 wichtige Bereiche eingeteilt. Der erste Bereich enthält Angaben die für die Webapplikation wichtig sind. Hier ist es z.B. die beiden Datumsformate um eine Kurz- und Langschreibweise des Datums festzulegen.

  1. [Application]
  2. dateformatlong = “%d. %B %Y”
  3. dateformatshort = “%d. %m. %Y”

Im zweiten Bereich werden alle wichtigen Zugangsdaten für die Datenbank hinterlegt. In meinen Fall ist das die Serveradresse (host), der Benutzername (user), das dazugehörige Kennwort (password) und der Datanbank-Name (db)

  1. [Database]
  2. host = “localhost”
  3. user = “demouser”
  4. password = “password”
  5. db = “redcms_advent”

Im letzten Bereich werden Informationen abgespeichert, die für das Anzeigen der Website wichtig sind. Da ich zur Zeit nur den Website-Titel und die Tagline brauche, habe ich auch das dort hingeschrieben.

  1. [Website]
  2. Title = “RE-Design”
  3. Tagline = “REDcms Advents”

Was muss nun die „Configuration“-Klasse nun alles machen? Im Grunde genommen nur diese „INI“-Datei in einen zweidimensionalen Array laden und Methoden anbieten auf die Werte der Konfiguration zuzugreifen.

Das Laden der Konfigurationsdatei geschieht im Konstruktor. Mit der Methode „getValue()“ und ihrem 2 Parametern für die Sektion und dem Schüssel bekommt man den entsprechenden Wert zurück. Falls man statt einen einzelnen Wert die gesamte Sektion als Array bekommen möchte, so kann man mit der „getSection()“-Methode dies tun.

  1. class Configuration
  2. {
  3. public $version = 1.0;
  4. private $file;
  5. private $config;
  6. public function __construct($file) {
  7. $this->file = $file;
  8. try {
  9. $this->config = parse_ini_file($file, true);
  10. } catch (Exception $e)
  11. < {
  12. die(‘Config-Error parseIni: ‘.$e.‘: ‘.$file);
  13. }
  14. }
  15. public function __destruct() {}
  16. public function getValue($key, $section) {
  17. return $this->config[$section][$key];
  18. }
  19. public function getSection($section) {
  20. return $this->config[$section];
  21. }
  22. }

Um die „Configuration“-Klasse nicht versehentlich mehrmals zu laden, könnte man sie innerhalb eines Updates als Singelton-Pattern anlegen und benutzen. Auch wäre später das Ändern von Konfigurationseinstellungen möglich, womit man dann schnell im Administrationsbereich das System anpassen könnte.

Downloads

Gestern hatte ich sehr ausführlich über die „Application“-Klasse geschrieben. Heute möchte ich über den Inhalt der „Request“-Klassen meines REDcms schreiben.

Die wichtigste Verarbeitung findet innerhalb des Konstruktors statt. Dem Konstruktor werden 2 Arrays als Parameter mit übergeben, wobei z.Z. nur der Erste wichtig ist. Es handelt sich hierbei um die „GET“-Werte der URL. Da ja per „mod_rewrite“ und „.htaccess“ Anhänge an die „index.php“-Datei gemacht werden.

Als erstes wird der Modus gesetzt, dabei kommen die 4 Klassenkonstanten Request::MODE_PAGE, Request::MODE_BOX und Request::MODE_MENU zum Einsatz.

Als nächstes wird die ID ausgelesen. Falls sie nicht vorhanden ist wird ihr Wert auf 1 gesetzt.

Zum Schluss wird versucht die Aktion aus dem „GET“-Wert zu ermitteln. Falls keiner vorhanden ist, wird standardmäßig die Aktion „show“ benutzt. Auch hier kommen wieder Klassenkonstanten zu Einsatz. Diesmal sind es aber 5 Stück: Request::ACTION_ADD, Request::ACTION_EDIT, Request::ACTION_UPDATE, Request::ACTION_DELETE und Request::ACTION_SHOW.

  1. function __construct($get, $request)
  2. {
  3. $this->request = $request;
  4. if (!empty($get['mode'])) {
  5. switch ($get['mode']) {
  6. case self::MODE_BOX:
  7. $this->mode = self::MODE_BOX;
  8. break;
  9. case self::MODE_MENU:
  10. $this->mode = self::MODE_MENU;
  11. break;
  12. default:
  13. $this->mode = self::MODE_PAGE;
  14. }
  15. } else {
  16. $this->mode = self::MODE_PAGE;
  17. }
  18. if (!empty($get['id']) && !is_nan($get['id'])) {
  19. $this->id = $get['id'];
  20. } else {
  21. $this->id = 1;
  22. }
  23. if(!empty($get['action'])){
  24. switch ($get['action']) {
  25. case self::ACTION_ADD:
  26. $this->action = self::ACTION_ADD;
  27. break;
  28. case self::ACTION_EDIT:
  29. $this->action = self::ACTION_EDIT;
  30. break;
  31. case self::ACTION_UPDATE:
  32. $this->action = self::ACTION_UPDATE;
  33. break;
  34. case self::ACTION_DELETE:
  35. $this->action = self::ACTION_DELETE;
  36. break;
  37. case self::ACTION_SHOW:
  38. default:
  39. $this->action = self::ACTION_SHOW;
  40. }
  41. } else {
  42. $this->action = self::ACTION_SHOW;
  43. }
  44. }

Warum arbeite ich nicht mit Strings sondern mit Konstanten, die ja auch Strings beinhalten? Durch die Verwendung von Konstanten gewährleiste ich, dass die Werte unverändert eingesetzt werden können. Ohne Angst haben zu müssen, dass sie versehentlich überschrieben werden. Auch kann ich so später aus den String-Konstanten relativ schnell z.B. Integer-Konstanten machen und die Verwendung bleibt gleicht.

Die restlichen Methoden dieser Klasse sind ausschließlich die „Getter“- und „Setter“-Methoden von Mode, ID und Action.

Downloads

Wie schon im gestrigen Artikel geschrieben, ist die „Application“-Klasse die Hauptklasse meines Systems. Sie sorgt für den reibungslosen Ablauf beim Anfordern einer Seite.

Wie funktioniert nun so was? Eigentlich recht simple. Die „index.php“-Datei, die automatisch bei jedem Request, also beim Aufrufen einer Seite, gestartet wird, initialisiert die „Application“-Klasse und speichert sie in der Variable $app ab. Somit habe ich die Möglichkeit jeder Zeit weitere Methoden dieser Klasse aufzurufen. Obwohl, eigentlich brauche ich nur 2 Stück, und auch die könnten rein theoretisch reduziert werden.

„init()“-Methode

Was passiert bei der Instanziierung? Der Konstruktor ruft die private Methode „init“ auf und diese lädt die zusätzlich benötigten Objekte. Zuerst wird aber das Datumsformat mit „setlocale(LC_ALL, ‘de’);“ gesetzt.

Danach wird in die „config“-Variable die „Configuration“-Klasse instanziiert. Diese lädt die Konfiguration, die in der „configuration.ini“-Datei hinterlegt ist. Um später auch eine HTML-Ausgabe benutzen zu können, wird die „Template“-Klasse anschließend in die „tpl“-Variable geladen. Ihr wird die Konstante mit dem Pfad zum Template-Ordner übergeben.In einer lokalen Variablen wird aus der Konfiguration der Array mit den Verbindungsangaben für die Datenbank geladen. Und in einer 2. lokalen Variablen wird der String vorbereitet der später für den Aufbau einer Datenbank-Verbindung wichtig ist. Nun wird die Verbindung zur Datenbank hergestellt und in der „db“-Variable abgespeichert. Nach einer Fehlerüberprüfung ob die Verbindung zum Datenbankserver hergestellt werden konnte, werden zum Schluss die Datumsformate auf der Konfiguration in das System integriert.

private function init()

{

setlocale(LC_ALL, ‘de’);

$this->config = new Configuration(‘./configuration.ini’);

$this->tpl = new Template(TEMPLATEPATH);

$db = $this->config->getSection(‘Database’);

$dsn = ‘mysql://’.$db['user'].‘:’.$db['password'].‘@’.$db['host'].‘/’.$db['db'];

$this->db = Database::connect($dsn);

$this->db->setFetchMode(DB_FETCHMODE_OBJECT);

if($this->db->isError($this->db))

{

die($this->db->getMessage());

}

Date::setLongFormat($this->config->getValue(‘dateformatlong’, ‘Application’));

Date::setShortFormat($this->config->getValue(‘dateformatshort’, ‘Application’));

}

„main()“-Methode

Nach der Initialisierung wird über die „index.php“-Datei die „main()“-Methode aufgerufen. Als erstes in dieser Methode wird die „Request“-Klasse in die „request“-Variable geladen. Ihr werden die globalen Variablen $_GET und $_REQUEST übergeben. Dies wird benötigt um anschließend über eine „switch“-Verzweigung zu entscheiden welche Informationen in die Klassenvariable „content“ geladen werden. Zum Schluss wird in die Klassenvariable „sidebar“ die Informationen zum Anzeigen der Sidebar gespeichert.

public function main()

{

$this->request = new Request($_GET,$_REQUEST);

switch ($this->request->getMode())

{

case Request::MODE_BOX:

$this->content = $this->getBox($this->request->getId());

break;

case Request::MODE_MENU:

$this->content = $this->getMenu($this->request->getId());

break;

case Request::MODE_PAGE:

default:

$this->content = $this->getPage($this->request->getId());

break;

}

$this->sidebar = $this->getSidebar($this->request->getId());

}

„getBox()“-, „getMenu()“-, „getPage()“-Methode

Alle drei Methoden besitzen den gleichen Aufbau, weshalb ich hier nur die „getPage()“-Methode erklären möchte.

Als erstes wird die passende Klasse in eine Klassenvariable geladen. Ihr wird die Verbindung zum Datenbankserver mitgegeben. Als nächstes wird über die „request“-Variable und ihrer „getAction()“-Methode entschieden, welche Aktion nun folgen soll. Dabei gibt es 4 zur Auswahl.

  • hinzufügen
  • ändern
  • löschen
  • anzeigen

Wobei die letzte Aktion generell immer aufgerufen wird, wenn keine Aktion vorhanden sein sollte. Die habe ich mit eingefügt, falls das System mal keine Aktion in der „request“-Variable findet. Anschließend wird aus der jeweiligen Klasse der Titel für die Titelleiste des Browsers angefordert um ihn später mit dem Titel des Systems zu kombinieren.

private function getPage($id=1)

{

$this->page = new Page($this->db);

$content = ;

switch ($this->request->getAction()) {

case Request::ACTION_ADD:

$content = $this->page->add();

break;

case Request::ACTION_EDIT:

$content = $this->page->edit($id);

break;

case Request::ACTION_DELETE:

$content = $this->page->delete($id);

break;

case Request::ACTION_UPDATE:

$content = $this->page->update();

break;

case Request::ACTION_SHOW:

default:

$content = $this->page->get($id);

break;

}

$this->titlebar = $this->page->getTitle();

return $content;

}

private function getBox($id=1)

{

$this->box = new Box($this->db);

$content = ;

switch ($this->request->getAction()) {

case Request::ACTION_ADD:

$content = $this->box->add();

break;

case Request::ACTION_EDIT:

$content = $this->box->edit($id);

break;

case Request::ACTION_DELETE:

$content = $this->box->delete($id);

break;

case Request::ACTION_UPDATE:

$content = $this->box->update();

break;

case Request::ACTION_SHOW:

default:

$content = $this->box->get($id);

break;

}

$this->titlebar = $this->box->getTitle();

return $content;

}

private function getMenu($id=1)

{

$this->menu = new Menu($this->db);

$content = ;

switch ($this->request->getAction()) {

case Request::ACTION_ADD:

$content = $this->menu->add();

break;

case Request::ACTION_EDIT:

$content = $this->menu->edit($id);

break;

case Request::ACTION_DELETE:

$content = $this->menu->delete($id);

break;

case Request::ACTION_UPDATE:

$content = $this->menu->update();

break;

case Request::ACTION_SHOW:

default:

$content = $this->menu->get($id);

break;

}

$this->titlebar = $this->menu->getTitle();

return $content;

}

„getSidebar()“-Methode

In der „getSidebar()“-Methode wird als erstes in der lokalen Variable „login“ die Anzeigebox für die Sidebar gespeichert. Danach wird das selbe mit der Navigationsbox gemacht.

Zum Schluss wird dann mit Hilfe der Variable „tpl“ ein Template gefüllt und an die „main()“-Methode zurückgegeben.

private function getSidebar($id=1)

{

$login = Login::getAdminBox();

$navi = $this->getMenuBox(0);

$this->tpl->load(‘sidebar.tpl.html’);

$this->tpl->set(‘##NAVIGATION##’, $navi);

$this->tpl->set(‘##LOGIN##’, $login);

return $this->tpl->get($id);

}

„getMenuBox()“-Methode

Hier wird einfach nur mit der „Menu“-Klasse der Navigationsbaum erstellt und an die „getSicebar()“-Methode zurückgegeben.

private function getMenuBox($page_id=1)

{

$content = ‘<h4>Navigation</h4>’;

$menu = new Menu( $this->db );

return $content.$menu->getTree( $page_id );

}

„display()“-Methode

Die letzte Methode innerhalb der „Application“-Klasse ist die „display()“-Methode. Auch diese wird ähnlich wie die „main()“-Methode von der „index.php“-Datei direkt aufgerufen. Hier laufen dann alle vorherigen Verarbeitungen zusammen.

Als erstes wird der Website-Titel aus der Konfiguration geladen. Danach wird dieser mit dem Seitentitel kombiniert.

Zum Schluss wird das Template geladen, mit den Informationen gefüllt und dann an die „index.php“-Datei zurückgegeben. Diese zeigt den Inhalt schließlich an.

public function display()

{

$website = $this->config->getSection(‘Website’);

$this->titlebar = $website['Title'].‘ – ‘.$this->titlebar;

$this->tpl->load(‘index.tpl.html’);

$this->tpl->set(‘##BASEURL##’, BASEURL);

$this->tpl->set(‘##TITLEBAR##’, $this->titlebar);

$this->tpl->set(‘##WEBSITETITLE##’, $website['Title']);

$this->tpl->set(‘##TAGLINE##’, $website['Tagline']);

$this->tpl->set(‘##CONTENT##’, $this->content);

$this->tpl->set(‘##SIDEBAR##’, $this->sidebar);

return $this->tpl->get();

}

Downloads

Um ein flexibles aber dennoch stabiles Programmiergerüst zu bekommen, habe ich mich für das objekt-orientierte Programmieren entschieden. Das bedeutet, das die gesamte Funktionalität des Systems in Klassen gekapselt ist. Es gibt insgesamt 12 Klassen.

Klassenübersicht

Klassenübersicht

In den folgenden Tagen werde ich die einzelnen Klassen näher erklären. An dieser Stelle möchte ich euch erstmal nur eine kleine Übersicht über die verwendeten Klasen geben.

  • Application
  • Request
  • Configuration
  • Database
  • Content
    • Page
    • Box
    • Menu
  • Template
  • Login
  • Editor
  • Date

Ich habe versucht möglichst wenige Klassen zu benutzen, um den Überblick bei der Entwicklung nicht zu verlieren. Wobei die „Application“-Klasse hier ein sehr zentrale Rolle spielt. Weitere wichtige Klassen sind „Page“, „Box“ und „Menu“. Sie beinhalten die eigentliche Verarbeitung der einzelnen Bereiche.

In der „Request“-Klasse werden die Angaben der URL, also der Adressierung verarbeitet. Um REDcms schnell anpassen zu können, habe ich mich für die Verarbeitung von einer externen INI-Datei entschieden. So bekommt der Administrator einen schnellen Zugriff auf die wichtigsten Einstellmöglichkeiten ohne großartig in den einzelnen Klassen suchen zu müssen.

Um eine einfache Trennung zwischen der Programmierung und den HTML-Dateien zubekommen benutze ich eine eigenen „Template“-Klasse. Sie stellt mir alle wichtigen Funktionen für das Verarbeiten zur Verfügung.

Mit der „Login“-Klasse wird die An- und Abmeldung am System geregelt. Weiterhin kann darüber geprüft werden ob ein Benutzer berechtigt, also angemeldet, ist eine Seite bzw. deren Informationen einzusehen.

Um die Datumsausgabe besser zu verarbeiten, habe ich mir eine Hilfsklasse „Date“ erstellt. Damit bin ich in der Lage den Timestamp in ein deutsche Datumsformat zu konvertieren.Und ich habe noch zwei weitere Hilfsklassen erstellt. Wobei ich bei der „Database“-Klasse nur eine Ableitung der „DB“-Klasse des PEAR-Framework und bei der „Editor“-Klasse eine Ableitung des FCKeditors.

Ich habe mich bei der Umsetzung meines REDcms für eine mySQL-Datenbank entschieden, da die Verwaltung relativ einfach ist und sie bei den meisten Provider installiert ist. Auch kann man von den Apachefriends ein kostenloses Paket mit Server und Datenbank herunterladen und installieren.

Da mein System zur Zeit noch sehr einfach strukturiert ist, reichen mir 3 Datenbank-Tabellen: Page, Box und Menu.

Page-Tabelle

Page Tabelle

Page Tabelle

In dieser Tabelle werden alle Informationen abgespeichert die für das Anzeigen einer einzelnen Seite wichtig sind. Wobei nur Basisinformationen abgespeichert werden, denn jede Seite kann ja beliebig viele zusätzliche Boxen haben.

Was wird also nun in dieser Tabelle abgespeichert? Natürlich erstmal die ID der Seite, die für die Adressierung wichtig ist. Weiterhin der Seitentitel, um auch dem Besucher der Website einen aussagekräftige Namen zu präsentieren. Auch habe ich mir überlegt das jede Seite die Möglichkeit hat einen Einführungstext abzuspeichern, sowie den Namen des Autors.

Um die einzelne Seite individuell zu gestalten, wird zusätzlich der Dateiname eines Templates mit abgespeichert.

Box-Tabelle

Box Tabelle

Box Tabelle

Zunächst einmal wird in jeder Box neben der eigenen ID auch die ID der Seite abgespeichert. Weiterhin gibt es auch die Möglichkeit einen Titel, einen Einführungstext und einen Haupttext abzuspeichern. Während der Titel und der Haupttext zwingend notwendig sind, ist der Einführungstext optional. So habe ich mir die Möglichkeit offen gehalten später Übersichtsseiten in mein REDcms hinzuzufügen.

<!– @page { margin: 2cm } P { margin-bottom: 0.21cm } –>Auch wird hier wieder eine Template-Datei gefordert, um die Gestaltung individuell anzupassen. Zusätzlich wird noch die Sortierung der einzelnen Boxen innerhalb der Seite mit abgespeichert. Diese Sortierung wird aber in der derzeitigen Version (1.0) noch nicht mitberücksichtigt. Ich habe aber vor in eine der nächsten Versionen auch die Sortierung mit zu implementieren.

Menu-Tabelle

Menü Tabelle

Menü Tabelle

Getrennt von den einzelnen Seiten speichere ich die Menüstruktur ab. Das hat den Vorteil, dass ich so Seiten anlegen kann, die nicht direkt in der Website erscheinen sollen, wie z.B. Übersichtsseiten mit Suchergebnissen oder die Folgeseite eines Formulars oder Fehlerseiten (404-Error, etc.). Auch kann ich so mehrere Menüpunkte auf ein und die selbe Seite verlinken, wenn es nötig sein sollte das der Inhalt öfters angezeigt werden soll.

Hier wird also, wie bei der Box neben der eigen ID auch die ID der Seite abgespeichert. Zusätzlich wird aber auch der anzuzeigende Name des Links und optional ein Titel abgespeichert.

Downloads

Da meine Application relativ klein ist, brauche ich nicht viele Hilfsfunktionen bzw. zusätzliche Dateien. Es werden lediglich 2 Dateien und selbst die können später bei den Optimierungsmaßnahmen vielleicht eingespart werden. Beide Dateien werden auf der obersten Ebene des Systems abgespeichert. So dass der Zugriff schnell stattfinden kann.

„include“-Datei

Zu einem ist das die „include“-Datei. Sie lädt über den Befehl „include_once()“ die einzelnen Dateien die für den reibungslosen Ablauf des Systems benötigt werden. Weiterhin enthält sie eine kleine Funktion, die ich nicht mehr missen möchte.

  1. function code($msg, $code=HTML_CODE)
  2. {
  3. $msg = print_r($msg, true);
  4. if($code == HTML_CODE)
  5. {
  6. $msg = htmlentities($msg);
  7. }
  8. echo '<div><pre>'.$msg.'</pre></div>';
  9. }

Sie ist sehr hilfreich, da es immer wieder vorkommt Quellcode, oder ähnliche Angaben im Browser zu veröffentlichen. Die Funktion erwartet mindestens einen Parameter – das was sie anzeigen soll. Der 2. Parameter ist hilfreiche wenn man HTML-Quellcode anzeigen möchte, da ja jeder Browser erstmal jeden Quellcode durch seine Render-Engine jagt und somit umwandelt. Standardmäßig wird jede Anzeige konvertiert, außer man setzt den 2. Parameter auf „HTML_RENDER“. Dabei handelt es sich, wie bei „HTML_CODE“ um eine Konstante, die 2. Datei definiert wird.

Auch habe ich noch eine 2. Hilfsfunktion eingebaut, sie aber später wieder daktiviert, weil sie bei den vielen Änderungen an der Struktur des Systems nur im Wege stand. Trotzdem möchte ich die hier kurz aufzeigen. Vielleicht kommt auch sie später wieder mit in die Application.

  1. function __autoload($class_name)
  2. {
  3. $path = str_replace('_','/',$class_name);
  4. $path = strtolower($path);
  5. require_once('./core/'.$path.'.php');
  6. }

„defines“-Datei

In der „defines“-Datei werden alle wichtigen Konstanten geladen, die das System und der Entwickler braucht. Gott sei dank sind das nur 4 Stück.

  1. define('HTML_RENDER', 0);
  2. define('HTML_CODE', 1);
  3. define('BASEURL', dirname($_SERVER['PHP_SELF']));
  4. define('TEMPLATEPATH', 'layouts');

Die ersten beiden Zeilen hatte ich ja gerade schon erklärt. Die Definition der BASEURL legt den absoluten Pfad zur Application fest. In meinen Fall ist das z.B. „http://www.re-design.de/weblabor/REDcms/demo“. So kann man später relativ schnell benötigte Dateien nachladen oder URL-Weiterleitungen programmieren.

Die letzte hat eigentlich das gleiche Ziel – schnell auf den Zielordner der Templates zuzugreifen. Wenn ich mir das aber hier jetzt näher ansehe, stelle ich fest dass es wohl auch sinnvoll wäre diese Definition in die Konfiguration des System auszulagern. So hat später der Verwalter des Systems schnelleren Zugriff um diesen Wert zu ändern. Vielleicht werden ich diese Angabe später noch optimieren.

Downloads

Die genaue Interaktion des Programmeres mit dem Benutzer ist sehr vielfältig. Als erstes kann man sich von dem Frontend, also dem Bereich den der normale Benutzer sieht, über eine Anmelde-Maske an das Backend, dem Administrationsbereich, anmelden.

Danach erscheinen im Administrationskasten 3 weitere Links, um eine neue Seite, eine neue Box oder einen neuen Menüpunkt anzulegen. Außerdem kann man über den Button „abmelden” sich vom Administrationsbereich wieder abmelden.

Weiterhin erscheint hinter jedem Seitentitel, jedem Boxtitel und jedem Menüpunkt zwei Icons. Eins um die Seite, die Box bzw den Menüpunkt zu bearbeiten und eins um es zu löschen.

Es gibt also auch bei meinem CMS die klassischen Möglichkeiten zur Verwaltung von Content: hinzufügen, bearbeiten und löschen.

Welche Idee steckt hinter diesen 3 Bereichen?

Als erstes war mir wichtig die einzelnen Seiten sehr flexibel zu halten. Dazu habe ich mir überlegt, dass die tatsächlichen Texte der Seite in einzelne Boxen zu verpacken. Dadurch kann eine Seite sehr individuell aufgebaut werden.

Seite-Angaben

Was beinhaltet nun eine Seite? Eigentlich nur ihren Seitentitel und den Namen des jeweiligen Templates. Alle weiteren Angaben wie Einleitungstext und Autor sind optional.

Box-Angaben

Auch in der Box gibt es nicht viele, zwingende Informationen. Hier sind es der Boxtitel, der Haupttext, der Name des jeweiligen Templates und die Auswahl zu welcher Seite die Box gehört. Optional kann aber auch hier ein Einleitungstext und die Position (die Stelle innerhalb der Boxauflistung in der Seite).

Menü-Angaben

Hier sind nur 3 Angaben zwingend notwendig: der Name des Menüeintrages, die Zuordnung zu eines bestehenden Seite und ob der Menüeintrag ein Untermenü eines bestehenden Eintrages ist. Optional kann der Link mit einem Titel belegt werden.

Weitere Angaben

In allen drei Bereichen besteht die Möglichkeit die Veröffentlichung zu verneinen und damit die Seite, die Box bzw. den Menüpunkt im Frontend nicht anzeigen zu lassen. Außerdem ist schon ein Eingabefeld eingebaut, welches später das Zugriffslevel, also die Berechtigung, definiert.

Downloads

Archive