=====A WikkaCake Example===== <<**{{color c="red" text="This page is deprecated."}}** This example assumes ""CakePHP"" 1.1. An updated version for WikkaCake 1.3 is in the works. **See also:** WikkaCake<< ===Overview=== If you have yet to read the WikkaCake page, I'd suggest starting there first. This is actually an extension of that page, and provides an example of a completely self-contained Wikka action that has been written using the [[http://www.cakephp.org | CakePHP]] framework. This is not a Cake tutorial. Instead, I will simply provide the code as-is and provide comments that are Wikka-specific. If one has already set up and tested an embedded WikkaCake environment, then this application should run unmodified (in fact, it is the exact code that's currently running on my own machine). All directory names are referenced from the top-level "caketest" directory. This application is a simple database management app for saving, modifying, and deleting servers. It was developed for managing the public nameserver DB on the [[http://opennic.jdcomputers.com.au | OpenNIC wiki]]. A publicly accessible version will be available shortly once testing is completed. **config/database.php** %%(php) var $default = array('driver' => 'mysql', 'connect' => 'mysql_pconnect', 'host' => 'localhost', 'login' => 'root', 'password' => 'root', 'database' => 'wikka_cake', 'prefix' => ''); %% //Comments:// This is the setup I use on my personal machine (no, it's not externally accessible, so I'm not giving away any state secrets here). Obviously, you will need to modify accordingly. If you haven't done so, simply copy ##config/database.php.default## to ##config/database.php## and modify that. Eventually, this will go away once I work on seamlessly accessing the Wikka DB authentication params. **public_access_servers.sql** %%(sql) CREATE TABLE IF NOT EXISTS public_access_servers ( id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, ip_addr VARCHAR(15) NOT NULL, internic_hn VARCHAR(50), opennic_hn VARCHAR(50), owner VARCHAR(50) NOT NULL, city VARCHAR(50), state CHAR(2), country CHAR(2) NOT NULL, email VARCHAR(50), last_verified DATE, comments LONGTEXT); %% //Comments:// This is the DB schema upon which the following code is based. If you modify this, there's a good chance you'll need to modify one or more files below. Note that Cake expect, by default, a primary key called "id". **models/server.php** %%(php) VALID_NOT_EMPTY, 'owner' => VALID_NOT_EMPTY, 'country' => VALID_NOT_EMPTY ); } ?> %% //Comments:// ##$useTable## reflects that fact that I've named my DB table in a non-conforming way. **controllers/servers_controller.php** %%(php) params['wakka']; //var $scaffold; /* function ServersController() { parent::__construct(); // This doesn't work, as the params array isn't yet // available at time of class object construction! //$this->wikka = parent::$this->params['wakka']; } */ function index() { $this->set('servers', $this->Server->findAll()); } function add() { if(false===$this->params['wakka']->IsAdmin()) { $this->redirect($this->base); } if(true===isset($this->data['Servers']['action']) && false!==strpos($this->data['Servers']['action'], 'Cancel')) { $this->redirect($this->base); exit; } uses('sanitize'); $sanitize = new Sanitize(); if(empty($this->data)) { $this->render(); } if(!empty($this->data)) { $sanitize->cleanArray($this->data); if($this->Server->save($this->data)) { $this->flash('Your entry has been saved.', '', 1); } else { $this->set('errorMessage', 'Please correct errors below.'); $this->render(); } } } function delete() { if(false===$this->params['wakka']->IsAdmin()) { $this->redirect($this->base); } if(isset($this->params['url']['id'])) { $this->Server->del($this->params['url']['id']); } $this->redirect($this->base); exit; } function modify() { if(false===$this->params['wakka']->IsAdmin()) { $this->redirect($this->base); } $id = null; if(isset($this->params['url']['id'])) { $id = $this->params['url']['id']; } if(empty($this->data)) { $this->Server->id = $id; $this->data = $this->Server->read(); } else { uses('sanitize'); $sanitize = new Sanitize(); if(empty($this->data)) { $this->render(); } if(!empty($this->data)) { $sanitize->cleanArray($this->data); if($this->Server->save($this->data)) { $this->flash('Your entry has been saved.', '', 1); } else { $this->set('errorMessage', 'Please correct errors below.'); $this->render(); } } } } } ?> %% //Comments:// Look back at the changes you made in your ##webroot/index.php## code. Remember this? %%(php) array('wakka'=>(object)$this) %% That is how the Wikka instance is passed into the Cake framework so it's accessible in the controller (where the business logic resides). The commented-out construction above indicates that due to the way the Cake core libraries are bootstrapped, the Wikka instance isn't available until *after* the constructor has been called. Nor can it be set as a ##var## (since only static assignments can be made to ##var##-declared variables). So you'll need to call your Wikka lib functions within each method from which you need access. I could have chosen to use the data filters provided by Wikka, but for simplicity sake I used the Cake built-in "sanitize" class. Also, note that the ##$this->flash(...)## call doesn't redirect properly due to some interaction between Wikka and Cake. The link displays just fine, but one has to actually click the link for the redirect to occur. **views/layouts/default.thtml** %%(html) %% //Comments:// We don't want Cake to output any additional HTML sections, as this is already handled by Wikka. **views/servers/index.thtml** %%(html)

Public Access Servers


params['wakka']->IsAdmin()): ?> params['wakka']->IsAdmin()): ?>
IP Addr InterNIC Hostname OpenNIC Hostname Owner City State Country Email Last Verified Comments
X  M
params['wakka']->IsAdmin()) { echo $html->link('Add server', $html->base.'?action=add'); } ?> %% //Comments:// Note that the Wikka instance is accessible in the views for whatever you might need it for. Also, because of the conflicting way in which Wikka and Cake handle the parsing of URLs, links must be generated using the format shown above. Attempting to format Cake links as per the Cake manual is sure to lead to abject failure. **views/servers/add.thtml** %%(html)

Add Server

IP Addr: input('Server/ip_addr', array('size'=>'15')) ?> tagErrorMsg('Server/ip_addr', 'IP address is required.') ?>

Owner: input('Server/owner', array('size'=>'50')) ?> tagErrorMsg('Server/owner', 'Owner is required.') ?>

City: input('Server/city', array('size'=>'50')) ?>

State/Province: input('Server/state', array('size'=>'2')) ?>

Country: input('Server/country', array('size'=>'2')) ?> tagErrorMsg('Server/country', 'Country is required.') ?>

Email (will be obfuscated): input('Server/email', array('size'=>'50')) ?>

Comments: textarea('Server/comments', array('rows'=>'2')) ?>

submit('Save') ?> submit('Cancel', array('name'=>'data[Servers][action]')) ?>

%% //Comments:// Handling the Cancel buttons was somewhat tricky. **views/servers/modify.thtml** %%(html)

Modify Server

hidden('Server/id'); ?>

IP Addr: input('Server/ip_addr', array('size'=>'15')) ?> tagErrorMsg('Server/ip_addr', 'IP address is required.') ?>

Owner: input('Server/owner', array('size'=>'50')) ?> tagErrorMsg('Server/owner', 'Owner is required.') ?>

City: input('Server/city', array('size'=>'50')) ?>

State/Province: input('Server/state', array('size'=>'2')) ?>

Country: input('Server/country', array('size'=>'2')) ?> tagErrorMsg('Server/country', 'Country is required.') ?>

Email (will be obfuscated): input('Server/email', array('size'=>'50')) ?>

Comments: textarea('Server/comments', array('rows'=>'2')) ?>

submit('Save') ?> submit('Cancel', array('name'=>'data[Servers][action]')) ?>

%% //Comments:// Straightforward, using the same trick as in ##add.thtml## to differentiate between Save and Cancel button clicks. ===Summary=== So, there you have it! A functioning DB application using Wikka as the presentation framework and [[http://www.cakephp.org | CakePHP]] as a modular MVC framework. Once one removes the ##config/database.php## file, this could be zipped/tarred up and distributed as a plugin action.