Datenbank-Anwendung mit Cake-PHP
Cake-PHP

DeveloperIT-ProjekteSoftware

Das MVC-Architekturmuster hält auch in der PHP-Welt Einzug: Mit Cake PHP sind Anwendungen ähnlich wie bei Ruby on Rails möglich – aber mit der zurzeit trendigsten Webskriptsprache.

Rollenaufteilung

Datenbank-Anwendung mit Cake-PHP

PHP gilt immer noch als die Webtechnik für Einsteiger, doch im professionelleren Bereich wird die Luft etwas dünner. Mit ASP.NET 2.0 gibt es einen sehr mächtigen Konkurrenten, und auch Ruby on Rails gewinnt stetig Anhänger dazu. Hauptnachteil dieser Konkurrenten: der immer noch geringe Marktanteil.

Doch die PHP-Fraktion hält nicht inne, und modernere Mittel der Software-Technik wie etwa Entwurfsmuster – ein mindestens zwölf Jahre alter Ansatz, der aber erst seit einiger Zeit in Mode kommt – werden gang und gäbe.

Ein spezielles Architekturmuster ist MVC, Model-View-Controller. Im Deutschen ist mit gleicher Bedeutung auch der Begriff MPS, Modell-Präsentation-Steuerung geläufig. Der Sinn des Ganzen besteht darin, die Anwendung in drei Rollen aufzuteilen:

– Model/Modell: Diese Komponente enthält die Daten einer Anwendung, dient also als Schnittstelle zur Datenbank.
– View/Präsentation: Darin wird die Anzeige realisiert, also im Web das HTML-Markup. Es sollte sich keinerlei Geschäftslogik in dieser Komponente befinden, nur Anzeigelogik.
– Controller/Steuerung: Diese Komponente steuert die gesamte Anwendung, kommuniziert mit dem Modell und liefert Daten an die Präsentationsschicht.

Das Herz einer Anwendung, die Geschäftslogik, wird je nach Anforderung entweder im Modell oder in der Steuerung untergebracht. Dieser Ansatz ermöglicht somit eine außergewöhnlich klare Rollenaufteilung bei der Entwicklung: Ein Datenbank-Administrator implementiert das Modell, ein Webdesigner kümmert sich um die Präsentation und ein Entwickler realisiert die Steuerung.

Gerade diese Gewaltenteilung ist das Herzstück des Web-Frameworks Ruby on Rails (RoR). Eine derart einfache Anwendung des MVC/MPS-Ansatzes war bis dato im Web noch nicht möglich. Das führt dazu, dass trotz der exotische Sprache Ruby das Framework RoR starke Zuwachszahlen genießt.

Doch MVC soll nicht weiterhin nur eine Domäne von Rails bleiben. Auch für PHP gibt es seit Längerem mehrere MVC-Implementierungen. Die bekannteste davon ist das Open-Source-Framework Cake PHP. Gewisse Ähnlichkeiten mit Rails kommen nicht von ungefähr. In diesem Workshop wird ein Teil einer Intranet-Anwendung, das Einreichen von Urlaubsanträgen, mit Cake PHP realisiert. Dabei werden Sie sehen, wie einfach und schnell Sie die drei Bereiche Modell, Präsentation und Steuerung mit PHP und Cake PHP erstellen. An manchen Stellen ist etwas zusätzlicher Code notwendig, denn PHP ist nicht von vornherein als MVC-Technik aufgebaut worden. Dennoch sind schnelle Ergebnisse möglich.


Installation und Vorbereitung

Datenbank-Anwendung mit Cake-PHP

Der erste Schritt geht hin zur Cake-PHP-Website, www.cakephp.org. Auf der recht bunten Seite gibt es diverse Versionen von Cake PHP zum Download, unter anderem auch Nightly Builds, also tagesaktuelle, aber nicht komplett getestete Versionen.

Empfehlenswert sind hier die als stabil gekennzeichneten Releases, die es unter cakeforge.org/frs/?group_id= 23 gibt – der Name Cakeforge ist natürlich an Sourceforge angelehnt, nicht nur namentlich.

Zum Redaktionsschluss gibt es von Cake PHP zwei stabile Versionen: eine zu Cake PHP 1.0 (1.0.1.2708) und eine zu Cake PHP 1.1 (1.1.3.2967). Für den Workshop sind beide Versionszweige geeignet, konkret verwendet wurde für diesen Artikel Cake PHP 1.1. Das Distributionsarchiv enthält im Wesentlichen drei Unterordner:

– app: zur Speicherung von eigenen Projekten
– cake: das eigentliche Cake-Framework
– vendors: leer, wird nicht verwendet

Entpacken Sie diese Struktur (inklusive der Dateien index.php und .htaccess im Hauptverzeichnis) in einen Unterordner cake in Ihrem Webverzeichnis. Geben Sie dann dem PHP-Prozess Schreibrechte auf das Verzeichnis app/tmp. Dann rufen Sie – etwa via http://localhost/cake/ – Cake PHP einmal auf und sehen eine Begrüßungsseite. Achtung, erst ab einer Bildschirmbreite von über 900 Pixeln ist das Design stimmig. Sollte die Seite auch bei großen Auflösungen derangiert aussehen, so klappt auf Ihrem System die Link-Umschreibung per mod_rewrite nicht richtig.

Ein schneller Workaround besteht darin, die Datei app/config/core.php zu bearbeiten. Entfernen Sie ungefähr in Zeile 40 die Kommentarzeichen am Anfang, so dass danach folgende Anweisung aktiv ist:

define ('BASE_URL', env('SCRIPT_NAME'));

Rufen Sie in diesem Fall noch einmal http://localhost/cake/ auf. Die Seite wird besser aussehen.


Die Datenbank

Datenbank-Anwendung mit Cake-PHP

Eine der großen Stärken – und gleichzeitig Schwächen – von Frameworks wie Cake PHP oder RoR liegt darin, dass eine direkte Abbildung zwischen Datenbank und Präsentation möglich ist. Mit anderen Worten: Es erfordert äußerst wenig Code, Daten in die Datenbank zu schreiben beziehungsweise sie auszulesen ? und erst recht kein SQL. Leider erfordert das auch die Einhaltung bestimmter Grundregeln in Bezug auf die Benennung. Also: Wie die Datenbank selbst heißt, ist unerheblich – im Beispiel wird urlaub gewählt. Der Name aller Datenbanktabellen muss ein englisches Pluralwort sein. Der für die Beispielanwendung nahe liegende Tabellenname antraege scheidet also aus. Das englische Äquivalent requests ist allerdings möglich. Dabei ist Cake PHP relativ schlau und kennt auch irreguläre Pluralwörter wie children als Mehrzahl von child. Auch aus baby wird im Plural babies.

Es gibt weitere, nicht unpraktische Vorschriften. Wenn die Tabelle einen Primärschlüssel hat, dann muss dieser id heißen. Dieser Name ist vorgegeben. Die Beispielanwendung verwendet eine Tabelle requests mit vier Feldern: einem Primärschlüssel, einem Urlaubsgrund sowie einem Start- und Enddatum. Bei den Feldnamen sind wieder beliebige Bezeichnungen und Sprachen möglich.


CREATE TABLE 'requests' (
'id' INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
'start' DATE NOT NULL ,
'ende' DATE NOT NULL ,
'grund' VARCHAR( 255 ) NOT NULL
) ENGINE = MYISAM ;

Im nächsten Schritt teilen Sie PHP mit, wo sich die Datenbank überhaupt befindet. In der Datei app/config/database.php.default finden Sie bereits einen Torso für die Einstellungen, den Sie an die lokalen Gegebenheiten anpassen und dann in database.php umbenennen. Im Array $default stehen dann die Verbindungsinfos zur Datenbank. In $test können Sie eine davon abweichende Konfiguration für Testzwecke angeben, was Sie aber in diesem Workshop nicht brauchen. Die grundlegenden Einstellungen sind driver (welche Datenbank) und connect (welche Verbindungsmethode, etwa mysql_connect oder mysql_ pconnect). In host, login und password stehen die Verbindungsdaten, database gibt den Namen der Datenbank an, und in prefix konfigurieren Sie ein eventuelles Präfix für die beteiligten Tabellen – praktisch, wenn beim Hosting-Paket nur eine Datenbank mit dabei ist.


class DATABASE_CONFIG
{
var $default = array('driver' => 'mysql',
'connect' => 'mysql_connect',
'host' => 'localhost',
'login' => 'Benutzer',
'password' => 'P@$$w0rt',
'database' => 'urlaub',
'prefix' => '');
}
?>

Im letzten Schritt – aus Datenbanksicht – erstellen Sie noch das Modell. Nun, im Grunde genommen ist die Tabelle selbst bereits schon Modell genug. Sie müssen diese im Wesentlichen nur noch bei Cake PHP anmelden. Dazu erstellen Sie im Ordner app/models die Datei request.php. Der Name bildet sich also aus dem Singular des Tabellennamens. In dieser Datei definieren Sie eine Klasse Request (Singular, beginnt mit einem Großbuchstaben) und erzeugen dort eine Klassenvariable $name, deren Wert identisch zum Klassennamen ist.

Außerdem erweitern Sie das Modell um bestimmte Vorgaben zu den Daten. Datumswerte liegen in MySQL im Format JJJJ-MM-TT vor. Das gilt im Beispiel natürlich für das Start- und das Enddatum jedes Urlaubsantrags. In der Klassenvariablen $validate können Sie für alle Datenbankfelder einen regulären Ausdruck angeben, der den Feldinhalt beschreibt. Später werden alle Eingaben, die nicht diesem Format entsprechen, vom System automatisch abgewiesen. Das führt letztendlich zu folgendem Modell in der Datei app/models/request.php:


class Request extends AppModel
{
var $name = 'Request';
var $validate = array(
'start' => '/^\d{4}-\d{2}-\d{2}$/',
'ende' => '/^\d{4}-\d{2}-\d{2}$/' );
}
?>

Das war auch schon der gesamte Datenbankteil!


Steuerung

Datenbank-Anwendung mit Cake-PHP

Der nächste Schritt beim Entwickeln der Anwendung widmet sich der Steuerung. Diese landet in der Datei app/controllers/requests_controller.php – diesmal wird also wieder der Tabellenname im Plural verwendet. In dieser Datei legen Sie eine Klasse RequestsController (Plural, groß geschrieben) an, die sich von AppController ableitet. Erneut benötigen Sie eine Klassenvariable $name, deren Wert diesmal ‘Requests’ ist – also Plural, nicht Singular wie im Modell.


class RequestsController extends AppController
{
var $name = 'Requests';

Des Weiteren erzeugen Sie im Modell bestimmte Aktionen, die dann per über den passenden URL aufgerufen werden. Die Standardaktion heißt index. In dieser können Sie alle gestellten Urlaubsanträge ausgeben. Das geht mit folgendem Code – achten Sie wieder auf Singular, Plural sowie Groß- und Kleinschreibung:


function index()
{
$this->set('requests', $this->Request->findAll());
}

Doch bevor es überhaupt Urlaubsanträge zum Ausgeben gibt, müssen diese erst erzeugt werden. Dazu ist eine weitere Aktion fällig, die neu heißt. Dazu wird es später ein Eingabeformular geben, doch das gehört eindeutig in die Präsentationsschicht. Im Controller schieben Sie lediglich die Daten aus dem Formular in die Datenbank – wenn im Formular überhaupt etwas drinsteht. Das erklärt die folgende Abfrage im Controller: Gibt es Daten (Schnellzugriff darauf in Form eines assoziativen Arrays via $this
->data
), so werden diese abgespeichert ($this->Request
->save($this->data)
). Am Ende gibt flash() eine Meldung aus und verlinkt auf die Hauptseite (/requests):


function neu()
{
if (!empty($this->data))
{
if ($this->Request->save($this->data))
{
$this->flash('Antrag ist eingegangen.', '/requests');
}
}
}
}
?>

Für den etwas eingeschränkten Funktionsumfang der Beispielanwendung reichen diese beiden Aktionen, was natürlich auch bedeutet, dass die Steuerung damit fertig implementiert ist.


Präsentation

Datenbank-Anwendung mit Cake-PHP

Das letzte Teilstück von MVC/MPS ist die Präsentationsschicht. In Cake PHP wird das mit Hilfe von Template-Dateien realisiert, die Dateiendung ist THTML. Tipp: Richten Sie Ihren Editor so ein, dass er THTML-Dateien als PHP-Dateien erkennt, dann können Sie auch dort das praktische Syntax-Highlighting nutzen. Denn obwohl es sich nur um die Darstellung handelt, ist dennoch PHP-Code möglich. Schließlich gibt es eine Ausgabelogik, also eine Vorschrift, wie und wo welche Daten auszugeben sind. Dank der vom Modell und der Steuerung vorab geleisteten Arbeiten ist nur wenig tatsächlicher Code notwendig.

Die THTML-Dateien enthalten das komplette HTML, das ausgegeben werden soll. Der Dateiname richtet sich nach dem Namen der Aktion im Controller. Für die Aktion index heißt also die Präsentationsdatei index.thtml und für die Neuanlage eines Urlaubsantrags neu.thtml.

Im PHP-Code kommt erneut der Name der Datenbanktabelle zum Einsatz: Das Array $requests enthält alle vom Modell gelieferten Daten und kann, etwa per foreach-Schleife, ausgegeben werden:


foreach ($requests as $request) {
...
}

Um jedoch Sicherheitslücken bei der Ausgabe – Stichwort Cross-Site Scripting (XSS) – zu verhindern, ist eine Ausgabekodierung Pflicht. Das geht entweder mit der PHP-Funktion htmlspecialchars() oder mit der speziellen Sanitize-Klasse von Cake PHP, die wie folgt geladen und initialisiert wird:


uses('sanitize');
$san = new Sanitize();

Danach kann innerhalb der foreach-Schleife jeder einzelne Urlaubsantrag ausgegeben werden. Jedes Array-Element innerhalb von $requests ist wiederum ein Array. Über den Index Request (groß geschrieben, Singular) erhalten Sie den Datensatz und beispielsweise das Start- und Enddatum. Mit den PHP-Funktionen date() und strtotime() wird das etwas ungewöhnliche Format JJJJ-MM-TT in TT.MM.JJJJ umgeformt:


printf('

  • %s (%s - %s)
  • ',
    $san->html($request['Request']['grund']),
    date('d.m.Y', strtotime($request['Request']['start'])),
    date('d.m.Y', strtotime($request['Request']['ende'])));

    Außerdem gehört auf das Template index auch noch ein Link auf die Seite zur Neuanlage. Je nach Konfiguration von Cake PHP ist dieser Link etwas anders gestaltet, aber die Hilfsmethode $html->link() ist hier nützlich: Sie generiert einen Link. Sie geben dabei im zweiten Parameter nur den Tabellennamen und die Aktion wie folgt an:


    echo $html->link('Neuer Antrag', '/requests/neu/');

    Ein wenig komplizierter ist die Vorlage für das Einreichen eines Urlaubsantrags, neu.thtml. Dort benötigen Sie zunächst ein HTML-Formular, das auf den richtigen URL postet. Eine weitere Hilfsmethode kommt zum Einsatz: $html->url().


    Dann geben Sie die einzelnen Formularfelder an. Der wohl häufigste Fall, Eingabefelder, wird via $html->input() erledigt. Als Parameter geben Sie zunächst das zugehörige Datenbankfeld an (als Präfix aber mal wieder: der Singular des groß geschriebenen Tabellennamens) sowie ein optionales Array mit HTML-Optionen. Erinnern Sie sich noch an die regulären Ausdrücke für die Datumsformate im Modell? Auf diese können Sie jetzt überprüfen, indem Sie – am besten nach jedem Feld – die Hilfsfunktion tagErrorMsg() aufrufen. Sie geben wieder die Bezeichnung des Feldes wie bei input() an sowie im zweiten Parameter eine Fehlermeldung. Wird das Format nicht eingehalten oder überhaupt nichts ins Feld eingegeben, erscheint beim Versand die angegebene Meldung.

    Mit $html->submit() erzeugen Sie schließlich eine Schaltfläche zum Formularversand. Als Parameter verwenden Sie die Beschriftung. Sie erhalten folgendes Template:


    Grund:
    echo $html->input('Request/grund', array('size' => '50'));
    echo $html->tagErrorMsg('Request/grund', 'Ohne Grund gibt es keinen Urlaub!');
    ?>

    Von:
    echo $html->input('Request/start', array('size' => '10'));
    echo $html->tagErrorMsg('Request/start', 'Wann soll es denn losgehen
    (jjjj-mm-tt)?');
    ?>

    Bis:
    echo $html->input('Request/ende', array('size' => '10'));
    echo $html->tagErrorMsg('Request/ende', 'Wann sind Sie wieder da
    (jjjj-mm-tt)?');
    ?>

    $html->submit('Antrag einreichen')
    ?>

    Das war es auch schon. Rufen Sie die Anwendung via http://localhost/cake/requests/ oder über http://localhost/cake/index.php/requests/ auf.


    Fazit

    Datenbank-Anwendung mit Cake-PHP

    Cake PHP ermöglicht MVC mit PHP, und auch hier liegen die größten Hürden beim Einstieg in das Architekturmodell und nicht in das Framework selbst. Für die Beispielanwendung sind viele Erweiterungen denkbar, etwa ein Rollenmanagement, das dann den Antragssteller automatisch erkennt und es einem Vorgesetzten erlaubt, den Antrag zu genehmigen oder abzulehnen.


    Alle Dateien und Listings zum Workshop finden Sie auf der Heft-CD und unter listings.internet-pro.de.