CakePHP Tutorial - Model und Controller - ein Gästebuch programmieren

CakePHP Tutorial - Model und Controller - ein Gästebuch programmieren
Von Lars Ebert am 03.06.13, 11:00
Kategorien: CakePHP, PHP, Programmieren and Tutorials

Seit dem letzen Teil der Artikelserie haben wir eine funktionierende statische Webseite, die auf CakePHP aufbaut. Bis jetzt ist dies jedoch noch nicht sonderlich spektakulär—interessant wird es erst, wenn wir nun etwas Dynamik ins Spiel bringen. Um uns mit den grundlegenden Funktionen von Modeln und Conrollern vertraut zu machen, beginnen wir mit einem einfachen Beispiel, nämlich der Programmierung eines Gästebuchs.

Am Ende dieses Artikels werden wir dann ein sehr einfaches und unkompliziertes Gästebuch haben, dass wir später noch weiter erweitern werden. Vorerst sollen uns aber ein möglichst einfaches Gästebuch reichen.

Worauf warten wir noch? Legen wir los!

Artikelserie: CakePHP-Tutorial: Web-Anwendung mit MVC

Dieser Artikel ist Teil einer mehrteiligen Artikelserie. Lies dir auch die restlichen Teile durch!

  1. CakePHP Tutorial: Grundfunktionen und Hallo Welt
  2. CakePHP Tutorial: Views, Layouts und Helpers
  3. CakePHP Tutorial - Model und Controller - ein Gästebuch programmieren
  4. CakePHP Tutorial: Admin-Routen und Login - erweitertes Gästebuch
  5. CakePHP Tutorial: Epsilon-Greedy-Tests - ein Plugin erstellen

Schritt 1: Wo speichern wir unsere Daten?

Als erstes müssen wir eine MySQL-Datenbank anlegen und hier eine Tabelle für unsere Gästebuch-Einträge erstellen. Wir nennen diese Tabelle »entries« und legen sie mit folgenden Feldern an:

Feldname Feldtyp
id bigint(20) unsigned Auto-Inkrement
author varchar(50)
ip varchar(50)
content longtext
created datetime

Sollten später noch weitere Felder benötigt werden, können wir diese einfach hinzufügen. Aber vorerst reichen diese Felder.

Schritt 2: Konfiguration der Datenbank-Verbindung

Bevor CakePHP auf die Datenbank zugreifen kann, müssen wir noch die Zugangsdaten konfigurieren. Dafür steht uns bereits eine Demo-Datei database.php.default zur Verfügung, diese müssen wir nur in database.php umbenennen und die Zugangsdaten hinterlegen.

<?php
class DATABASE_CONFIG {
	public $default = array(
		'datasource' => 'Database/Mysql',
		'persistent' => false,
		'host' => 'localhost',
		'login' => 'root',
		'password' => '###########',
		'database' => 'caketut',
		'prefix' => '',
		'encoding' => 'utf8',
	);
}

Das wars schon!

Schritt 3: Das Model kommuniziert mit der Datenbank

Als nächstes legen wir das Entry Model an.

<?php
	
	class Entry extends AppModel
	{
		public $name = 'Entry';
	}
	
?>

Bisher macht dieses Model noch nichts, aber hier können wir später zum Beispiel die Validierung von Eingaben durchführen. CakePHP stellt dem Model außerdem jede Menge praktischer Methoden zur Verfügung. Mit diesen können wir sehr einfach auf die Daten der Datenbank zugreifen und neue Daten speichern!

Dazu aber später mehr!

Schritt 4: Der Controller als zentrale Anlaufstelle

Nun müssen wir noch den EntriesController erstellen:

<?php
	
	class EntriesController extends AppController
	{
		public $name = 'Entries';
		
		public function index() {
			
		}
	}
	
?>

Auch hier gibt es bisher noch nicht viel zu sehen. Für CakePHP ist aber wichtig, dass es diesen Controller gibt — hier werden nämlich später die Gästebuch-Einträge verwaltet. Die Action »index« können wir jetzt schon einmal über das Routing ansprechen:

<?php
	
	Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
	Router::connect('/guestbook', array('controller' => 'entries', 'action' => 'index'));
	Router::connect('/*', array('controller' => 'pages', 'action' => 'display'));
	
	CakePlugin::routes();
	
	require CAKE . 'Config' . DS . 'routes.php';

Wir weisen der gerade angelegten Aktion also die URL /guestbook zu.

Schritt 5: Jede Action braucht einen View!

Damit CakePHP die Action rendern kann, muss es auch noch einen View zur Action geben! Diesen View legen wir jetzt an.

<h1>Das Gästebuch</h1>

Damit wir diese Seite auch aufrufen können, müssen wir sie noch zur Navigation hinzufügen.

class NavHelper extends AppHelper
{
	public $name = 'Nav';
	
	public $helpers = array('Html');
	
	private $navItems = array(
		array(
			'title' => 'Startseite',
			'url' => array('controller' => 'pages', 'action' => 'display', 'home')
		),
		array(
			'title' => 'Gästebuch',
			'url' => array('controller' => 'entries', 'action' => 'index')
		),
		array(
			'title' => 'Beispiele',
			'url' => array('controller' => 'pages', 'action' => 'display', 'beispiele')
		)
	);
	
	[...]
	
}

Im Frontend können wir jetzt in der Tat eine neue Seite mit der Überschrift »Das Gästebuch« sehen.

Schritt 6: Der Form-Helper von CakePHP

Jetzt folgt einer der Gründe, wieso CakePHP ein geniales Framework ist - der FormHelper. Der kümmert sich nämlich fast automatisch um die Ausgabe von Formularen und Fehlermeldungen, was wir uns jetzt Zunutze machen.

<h1>Das Gästebuch</h1>
<?php echo $this->Form->create(); ?>
	
<?php echo $this->Form->end('Absenden'); ?>

Mit diesen beiden Zeilen können wir das Formular beginnen und enden. Mit create() geben wir den Start-Tag für das Formular aus. Da wir uns hier in einem View für den EntriesController befinden, weiß der FormHelper, dass er ein Formular für einen Gästebuch-Eintrag anlegen muss. Mit end() wird das Formular wieder geschlossen. Als ersten Parameter können wir einen String übergeben, wodurch ein Submit-Button mit dem String als Beschriftung ausgegeben wird.

Als nächstes müssen wir noch die Formular-Felder anlegen!

<h1>Das Gästebuch</h1>
<?php echo $this->Form->create(); ?>
	<?php echo $this->Form->input('author', array(
		'label' => 'Name',
		'placeholder' => 'Dein Name'
	)); ?>
	<?php echo $this->Form->input('content', array(
		'label' => 'Inhalt',
		'placeholder' => 'Was möchtest du ins Gästebuch schreiben?'
	)); ?>
<?php echo $this->Form->end('Absenden'); ?>

Mit der Methode input können wir den FormHelper ein Formularfeld generieren lassen. CakePHP bestimmt dabei automatisch anhand des Typs des Tabellenfeld den benötigten Feld-Typ. Die Spalte »author« hat als Typ varchar, deshalb spuckt CakePHP ein Text-Inputfeld aus. Das Feld »content« ist vom Typ text, also spuckt CakePHP eine Textarea aus.

Aber der FormHelper kümmert sich automatisch noch um viel mehr: Zum Beispiel füllt er die Felder automatisch mit den vorherigen Nutzereingaben, wenn das Formular nach dem Absenden noch einmal angezeigt werden muss, weil der Nutzer zum Beispiel einen Fehler gemacht hat. Auch die Fehlermeldungen werden vom FormHelper automatisch angezeigt!

Ich habe noch etwas CSS hinzugefügt, mein Gästebuch sieht nun so aus Ich habe noch etwas CSS hinzugefügt, mein Gästebuch sieht nun so aus

Schritt 7: Validation der Nutzereingaben - CakePHP-Validation

Auch um das Validieren von Nutzerdaten kümmert sich CakePHP fast selbstständig. Wir müssen nur festlegen, welchen Anforderungen die Eingaben entsprechen müssen. Dies können wir im EntriesModel definieren:

<?php
	
	class Entry extends AppModel
	{
		public $name = 'Entry';
		
		public $validate = array(
			'author' => array(
				'rule' => 'notEmpty',
				'required' => true,
				'message' => 'Bitte gib deinen Namen ein!'
			),
			'content' => array(
				'rule' => 'notEmpty',
				'required' => true,
				'message' => 'Was möchtest du ins Gästebuch schreiben?'
			)
		);
	}
	
?>

Wir können pro Tabellen-Feld nun Validations-Regeln festlegen. Ich habe hier zum Beispiel definiert, dass sowohl der Autor als auch der Inhalt nicht leer gelassen werden dürfen. Validation-Rules sind sehr komplex, ich empfehle dazu die Lektüre des Kapitels über Data Validation im CakePHP-Cookbook.

Für unser Gästebuch reichen jedoch diese einfachen Regeln, so kann der Nutzer die Felder nicht einfach leer lassen.

Schritt 8: Speichern der Gästebuch-Enträge

Das generierte Formular sendet die Eingaben wieder zurück an den EntriesController. In der Action index() können wir nun die Nutzereingaben einfach validieren und speichern!

<?php
	
	class EntriesController extends AppController
	{
		public $name = 'Entries';
		
		public function index() {
			if($this->request->is('post')) {
				if($this->Entry->save(
					$this->request->data,
					true,
					array('author', 'content', 'ip')
				)) {
					$this->Session->setFlash('Dein Eintrag wurde gespeichert!');
					$this->request->data = array();
				} else {
					$this->Session->setFlash('Dein Eintrag konnte nicht gespeichert werden. Prüfe deine Angaben!');
				}
			}
		}
	}
	
?>

Mit $this->request->is('post') prüfen wir, ob das Formular abgesendet wurde. Anschließend können wir einfach die save-Methode des Entry-Models aufrufen. Dieser Methode übergeben wir als ersten Parameter die Nuztereingaben, die sich dank CakePHP schon in der Variable $this->request->data befinden. Der zweite Parameter schaltet die Validation an. Mit dem dritten Parameter können wir definieren, welche Tabellen-Felder gespeichert werden dürfen. So können wir verhindern, dass mittels eines manipulierten Requests andere Felder gespeichert werden können.

Die Methode gibt nur true zurück, wenn die Validation funktioniert hat und der Eintrag gespeichert wird. Mit setFlash können wir eine Nachricht definieren, die dem Nutzer angezeigt werden soll. Dies funktioniert auch, wenn der Nutzer zwischen der Definition der Nachricht und der Ausgabe zu einem anderen Controller oder einer anderen Action weitergeleitet wird. Wir definieren hier eine Nachricht, ob der Eintrag gespeichert wurde oder nicht. Diese müssen wir allerdings noch im View anzeigen:

<h1>Das Gästebuch</h1>
<?php echo $this->Session->flash(); ?>
<?php echo $this->Form->create(); ?>
	<?php echo $this->Form->input('author', array(
		'label' => 'Name',
		'placeholder' => 'Dein Name'
	)); ?>
	<?php echo $this->Form->input('content', array(
		'label' => 'Inhalt',
		'placeholder' => 'Was möchtest du ins Gästebuch schreiben?'
	)); ?>
<?php echo $this->Form->end('Absenden'); ?>

Der FormHelper zeigt außerdem bei jedem Feld, für dass die Validation gescheitert ist, eine passende Fehlermeldung an!

Jetzt müssen wir nur noch die restlichen Tabellen-Felder automatisch ausfüllen lassen:

<?php
	
	class Entry extends AppModel
	{
		public $name = 'Entry';
		
		public $validate = array(
			'author' => array(
				'rule' => 'notEmpty',
				'required' => true,
				'message' => 'Bitte gib deinen Namen ein!'
			),
			'content' => array(
				'rule' => 'notEmpty',
				'required' => true,
				'message' => 'Was möchtest du ins Gästebuch schreiben?'
			)
		);
		
		public function beforeSave($options = array()) {
			if(!isset($this->id)) {
				$this->data['Entry']['ip'] = $_SERVER['REMOTE_ADDR'];
				
				$this->data['Entry']['content'] = preg_replace('|(?<!</p>)\s*\n|', "<br />", (preg_replace('/\n?(.+?)(\n\n|\z)/s', "<p>$1</p>", (preg_replace("/\n\n+/", "\n\n", preg_replace("/(\r\n|\n|\r)/", "\n", $this->data['Entry']['content']))))));
				
			}
			
			return parent::beforeSave($options);
		}
	}
	
?>

Die Methode beforeSave() wird vor dem Speichern automatisch aufgerufen. Hier schreiben wir nun einfach zu den Nutzerdaten noch die IP und wandeln die Umbrüche im Inhalt in Absätze um. So einfach ist das!

Nun können die Nutzer also schon Gästebuch-Einträge hinterlassen. Diese werden jedoch noch nirgends angezeigt. Dies ändern wir jetzt im letzten Schritt!

Schritt 9: Anzeigen der Gästebuch-Einträge

Dank CakePHP ist die Anzeige der Einträge auch sehr einfach. Als erstes müssen wir die Einträge vom Model erfragen:

<?php
	
	class EntriesController extends AppController
	{
		public $name = 'Entries';
		
		public function index() {
			if($this->request->is('post')) {
				if($this->Entry->save(
					$this->request->data,
					true,
					array('author', 'content')
				)) {
					$this->Session->setFlash('Dein Eintrag wurde gespeichert!');
					$this->request->data = array();
				} else {
					$this->Session->setFlash('Dein Eintrag konnte nicht gespeichert werden. Prüfe deine Angaben!');
				}
			}
			
			$entries = $this->Entry->find('all', array(
				'order' => 'created DESC'
			));
			
			$this->set('entries', $entries);
		}
	}
	
?>

Mit find() bekommen wir die Einträge vom Model. Der erste Parameter definiert, welche Einträge wir wollen - alle ('all') oder nur den ersten ('first'). Mit dem zweiten Parameter können wir Optionen festlegen, wie zum Beispiel Bedingungen oder die Sortierung. Wir definieren hier, dass die Einträge absteigend nach dem Datum sortiert werden. Anschließend übergeben wir die Einträge mit set an den View.

<h1>Das Gästebuch</h1>
<?php echo $this->Session->flash(); ?>
<?php echo $this->Form->create(); ?>
	<?php echo $this->Form->input('author', array(
		'label' => 'Name',
		'placeholder' => 'Dein Name'
	)); ?>
	<?php echo $this->Form->input('content', array(
		'label' => 'Inhalt',
		'placeholder' => 'Was möchtest du ins Gästebuch schreiben?'
	)); ?>
<?php echo $this->Form->end('Absenden'); ?>

<?php foreach($entries as $entry) { ?>
	<article class="entry">
		<div class="meta">
			<?php echo $entry['Entry']['author']; ?>
			<time><?php echo date('j. n. Y \u\m H:i \U\h\r', strtotime($entry['Entry']['created'])); ?></time>
		</div>
		<div class="content">
			<?php echo $entry['Entry']['content']; ?>
		</div>
	</article>
<?php } ?>

Die Ausgabe der Einträge ist trivial, die Einträge können wir einfach aus dem Array $entry auslesen und ausgeben.

Ich habe noch etwas CSS hinzugefügt und mein Gästebuch ist fertig. Ich habe noch etwas CSS hinzugefügt und mein Gästebuch ist fertig.

Ausblick

Unser Gästebuch funktioniert jetzt schon sehr gut. Im nächsten Teil der Artikelserie gehen wir etwas weiter in die Tiefe mit Modeln und Controllern, außerdem werden wir uns anschauen, wie wir einen Admin-Bereich erstellen können, in dem wir die Einträge moderieren können. Doch mehr dazu im nächsten Artikel.

Wenn dir der Artikel gefallen hat, schreib mir einen Kommentar oder teile ihn bei Facebook, Twitter oder Google+!

Nächster Artikel der Serie

Dieser Artikel ist Teil der Artikelserie »CakePHP-Tutorial: Web-Anwendung mit MVC«.

Hier geht es zum nächsten Artikel der Serie: CakePHP Tutorial: Admin-Routen und Login - erweitertes Gästebuch