Intro
Here at MYKITA we use CakePHP for keeping all the programming neat and tidy. It is a great framework for developing advanced web applications and it really helps you understanding your code even if you haven’t looked at it for a while.
CakePHP is a PHP framework so the focus of it is on delivering HTML pages … yes, there are Javascript helper and such, but after all, you’ll be dealing with standard web pages.
Enter ExtJS, a fantastic Javascript framework for creating user interfaces very close to what you might know from your standard desktop. Check out this or this demo if you want to see what I’m talking about … pretty cool, huh?
So wouldn’t it be nice if you could harness the powers of both frameworks and and combine the server-side benefits of Cake with the nice user interface features of Ext?
This is why I have created CakeXT, an extension that helps you glueing the two together.
When you’re finished with this tutorial, you’ll be able to create interfaces like the one below. Mind you, this is all HTML … not Flash, AIR or anything else.
The problem with ExtJS is (if you’ve got a webdesigner/PHP coder background), that it behaves very different to what you’ve learned the last few years. In short, apart from the lonely <body> tag in your HTML code, ExtJS will handle all the HTML code creation for you. It’ll give you data grid views (sort of a classic table on steroids), draggable window panels, drag-and-drop support, you name it.
So most of the application view logic (ie. what the user will have on his screen) will live in the user’s browser as fairly sophisticated JavaScript code. After the the first initial download of the ExtJS framework, the stylesheets and the HTML frame into the user’s browser cache, there will be no more communication between user and server.
No more? Ok, that’s not quite right … with a MVC framework like CakePHP, we’re gonna have some sort of data stored in a database. Ext speaks to the server (via a background Ajax call) and receives the entries in the database in a special format (JSON or XML, to be precise), processes them and displays them on the users screen. There is no HTML involved in all this, the server spits out plain data objects.
The problem with these two frameworks is, that they expect some things to be in a certain format … CakePHP even uses the slogan “Conventions over configuration”. Unfortunately, ExtJS has a very different idea about how these conventions should look like.
On order to make them understand each other we have to create two helpers:
- The Cake Helper tells Ext about about the database structure, ie. what fields there are and of what type they are
- The Ext Helper (ok it’s technically not a helper but an extended class, but it sort of comes down to the same thing) reads the data coming from Cake and displays it. It also creates forms in a way that, when submitted to Cake, are understood by the server.
A big advantage of this automated approach is, that if you add a field to a database table, Ext will know about this automatically and use the new field without any further action required on your side. In a traditional Cake application you’d have to change some views in order to get your database changes reflected.
I’d also like to point out that the CakeXt helper is fully compatible with Data Validation. If Cake doesn’t like the contents of a form field, Ext will show a meaningful error message to the user.
Quick start …
The projects homepage is at http://cakext.mykita.com. This is where you can find the latest source code, submit errors and track the project’s progress. Since CakeXt doesn’t quite work out of the box but requires some tweaking on the Cake side, I’ve created a demo package that includes all the files required to get you going. You can download it here.
Unzip it into a folder named cakext under your webserver’s root directory, import the included database.sql demo data into your database and edit /app/config/database.php to suit your needs.
Try opening http://localhost/cakext … you should get all greens if your configuration is correct. If not please check your settings in database.php again.
Next step would be opening http://localhost/cakext/pages/extbase. There you should find the Ext panel with our demo data. It consists of 3 tabs containing a list of Actors, Directors and Movies. They are related to each other, namely a movie has one director (belongsTo Relation) and every movie can have multiple actors (HABTM relation). All this is displayed by Ext accordingly.
Feel free to play around with the demo but since you’ll probably want to use CakeXt for your own project, we should have a look under the bonnet, shall we?
…and the inner workings
Models
Have a look at the files in /app/models. Nothing special in here, you define your model’s relations and the validation rules for your data entries. You can use bake to create these files.
Controllers
Every class must have 3 methods (index,ext_item and delete) for manipulating the database entries. Index is pretty straightforward, you pull the model’s data and the number of entries like this
function index() {
$this->Director->recursive = 1;
$this->set('directors', $this->Director->find("all"));
$this->set('movies', $this->Director->Movie->find("list"));
$this->set('total',$this->Director->find("count"));
}
The ext_item method is used to modify or create new entries. If the passed id is 0 then a new entry is assumed.
function ext_item($id = null) {
if(!empty($this->data)) {
if($this->Director->save($this->data))
{
$this->set('success','true');
$this->data = array();
return;
}
else {
$this->set('success',"false");
return;
}
}
if(empty($this->data) AND is_numeric($id)) {
$this->set('success','true');
$this->data = $this->Director->read(null, $id);
}
if ($id == 0 AND empty($this->data)) {
$this->set('success','true');
$this->data = array();
}
}
Also delete is very simple, it deletes an entry and passes true on success to the view.
View
We don’t use any standard html views, only json ones (they live in the views json directory).
index.ctp
<?php echo '{"total":'.$total.', "directors":'.$javascript->Object($directors).',"movies": '.$javascript->Object(movies).'}'; ?>
ext_item.ctp
{ "success" : <?php echo $success ?>, "data" : <?php echo $javascript->object($this->data) ?>, "validationErrors" : <?php echo $javascript->object($this->validationErrors) ?>}
delete.ctp
{ "success" : <?php echo $success ?> }
Ext layout
We’ll use a special layout that’ll include all the Javascript dependencies. Have a look at /app/views/layouts/ext.ctp. There we load the Ext css files, the base libraries and some helper classes, namely:
- Ext.ux.grid.RowAction by Josef Sakalos for editing/deleting grid rows
- Ext.ux.DDView by Nigel “Animal” White (is needed for Multiselect)
- Ext.ux.Multiselect by tjstuart for multiselect form fields (word it that this is in ext already, couldn’t get it to work)
- Ext.ux.xcheckbox by Josef Sakalos fixes Ext default behaviour with checkboxes
Thanks for your terrific work and help
Back to the plot, last but not least we include the Ext.ux.CakePanel class.
Ext base page
We are almost there, our CakeXt application takes off at /app/views/pages/extbase.ctp
<?php
$this->layout = "ext";
App::import('Helper','Ext');
$ext = new ExtHelper();
$this->pageTitle = "CakeXt Demo Page";
?>
Here we use above layout and import our Ext helper class. This is how we auto-create a configuration object for the CakePanel class from Cake
var moviesConfig = <?php echo $ext->createExtConfigObject( array('director_id' => 'Director'),"Movie",'movies') ?>
var movies = new Ext.ux.CakePanel(moviesConfig);
The createExtConfigObject takes a number of arguments. The first array is for making the Ext output more readable, we want Director as column and form field title, not director_id. Movie and movies are required in this case because when called from the Pages controller, the helper doesn’t know which classes to work on.
CakePanel returns a standard Ext Panel which we then can append to another component, a TabPanel in this case
new Ext.Viewport({
layout: 'fit',
items: [
new Ext.TabPanel({
activeTab: 0,
items: [movies,actors,directors],
bbar: [{xtype: 'tbtext',text: 'Please note ... demo data is reset after 1 hour!'}]
})
],
});
Caveats
Ext is a bit picky about the json data returned. The demo will only work if DEBUG is set to 0. If you want to debug your application and still have working json data open /app/webroot/index.php and find
if (Configure::read() > 0) {
echo "<!-- " . round(getMicrotime() - $TIME_START, 4) . "s -->";
}
Delete or comment out the echo line, this causes json to break.
You need to tell Cake to parse the .json file extension, this is done by adding
Router::parseExtensions('json');
to /app/config/routes.php
Also we need a layout for the json views, create /app/views/layout/json/default.ctp
<?php header('Content-type: text/html;charset=utf-8'); ?>
<?php echo $content_for_layout; ?>
Progess
Once you’ve got the workings of Ext figured out a bit better, it’s quite easy to implement more features. Things that are still missing or would be nice to have:
- Reordering of columns/fields from the helper
- Paging of entries
- Grouping of entries (makes sense for belongsTo data)
- Filtering toolbar
I hope CakeXt is usefull for some people, drop me a line if you have any suggestions, comments etc.
flow











Flow, Sorry, my bad …i understand that i have to use a hasMany through relationship not a habtm,
but i dont understarnd how to create a EditorGridPanel on the helper :S i want that to save all the data at once :s
and not save a register one by one selecting an id
Can you explain that please,
Thanks.