RSS

Neil Crookes

Learnings and Teachings on Web Application Development & CakePHP

Apr

17

Customising Baked Views in CakePHP

An introduction to how you go about customising CakePHP’s bake templates with some simple very simple examples. Part of a series of posts about customising bake templates and tasks.

Share and Enjoy:

  • Digg
  • del.icio.us
  • StumbleUpon
  • Technorati
  • Slashdot

Code generation is one of Cake’s most awesome features. I use it massively in all my applications.

Over time I noticed I was making the same small tweaks to all the baked files, in all my apps and thought, there must be a better way – of course there is!

This post covers how you go about customising your baked views and suggests some very simple tweaks that may be useful for you.

This will be the first in a series of posts that will cover some more complex possibilities, exploring customising the model, view and controller tasks as well as the templates, so stay tuned.

Rolling your own (well actually just tweaking someone else’s)

The template files that bake uses to build the views are located in /cake/console/libs/templates/views.

There are the following template files:

  • form.ctp (used for add/edit views)
  • home.ctp (used in pages/home view)
  • index.ctp (used in index views)
  • view.ctp (used in view views)

Copy the ones you want to customise to a /vendors/shells/templates/views folder. Note, you should not edit the core ones directly, Cake provides you with opportunities to override the core files at app and global levels. The above folder is for multiple applications that use the same core cake folder. If you wanted to customise templates for one application only, you can put them in /app/vendors/shells/templates/views.

This tutorial will focus on the form.ctp and index.ctp templates.

How does baking views work?

If you open them in your preferred editor you will see the templates are essentially just regular old HTML files with PHP code mixed in, that get parsed and populated with data.

The PHP code also outputs PHP code as strings however. For example, let look at the first 2 lines of code in the index.ctp template:

<div class="<?php echo $pluralVar;?> index">
<h2><?php echo "<?php __('{$pluralHumanName}');?>";?></h2>

As you can see, there is markup (e.g. “<div”…), and there is PHP code (e.g. “<?php echo $pluralVar;?>”) and there is also PHP code that echoes PHP code as a string (e.g. “echo “<?php…” ).

Essentially, the bake task gets a load of data about the controller and model you are baking the views for, then include()’s the template file. The output is caught using output buffering and written to a file instead of stdout.

The variables available for use in the templates by default are:

string $modelClass
string $primaryKey
string $displayField
string $singularVar
string $pluralVar
string $singularHumanName
string $pluralHumanName
array $fields
array $associations

The fields array is simply an array of field names in your model indexed numerically. E.g. $fields = Array[‘id’, ‘name’, ‘created’, ‘modified’]

The associations array is a multidimensional array containing keys for the association type, i.e. belongsTo, hasOne, hasMany, and hasAndBelongsToMany, the association key (e.g. the model name of the association) and data for the association primaryKey, displayField, foreignKey and controller (which are strings) and fields (which is an array as above) for each of this model’s associations.

Some sample simple tweaks

You may want to customise your templates in many ways, I’ll cover a couple of things that I like to do, which should give you an idea about how to do anything you might want to do too.

Note, I typically only use baked views for my admin system, which all look pretty much the same and really only differ by the fields that each model has.

The first customisation I want to make is to omit certain fields from the index view that I typically have in most models, but are just not relevant for display on these screens. Such fields include ‘created’, ‘created_by’, ‘deleted’, ‘deleted_by’, ‘active’ (i.e. enabled or disabled).

A simple way to do this would be to add the following code inside the 2 loops that display the field names in the column headings, and the record values in the table rows:

<?php
  if (in_array($field, array(
    'id',
    'active',
    'password',
    'created',
    'created_by',
    'deleted',
    'deleted_by',
  ))) {
    continue;
  }
?>
Default Baked Index Screen Columns omitted

Another quick customisation I like to do is having the actions div above the results table, rather than below it – so all you’ve got to do is cut and paste.

Moved List of Actions

You can do similar things in the form.ctp template, i.e. omitting fields that are always managed in other ways. For example, I prefer to show the current ‘active’ status of a record with red and green icons in the actions column of the index view, and clicking on the icon toggles the status between active and inactive (or 1 and 0). In addition, I have behaviors that automatically manage the created_by, modified_by, deleted and deleted_by data for me, so I don’t want inputs for those fields in my forms.

Default Baked Form Omitted Fields

OK, so I’ve covered how its done and provided a couple of very simple example customisations, coming soon will be more of the same, but a lot cooler.

Share and Enjoy:

  • Digg
  • del.icio.us
  • StumbleUpon
  • Technorati
  • Slashdot
(2 votes, average: 4.50 out of 5)
Loading ... Loading ...

8 Responses so far

Your post is great! How do you control the fields like active throw a behaviour?

Regards!!

Hi David, thanks for your comment. For the active field I tend to show the current ‘active’ status of a record with red or green icon in the actions column of the index view, and clicking on the icon toggles the status between active (green) and inactive (red).

To do this I just add a method to the app_controller like this (untested, but you get the idea):

[Edit: fixed bug, thanks david]

function change_status_to($toStatus = null, $id = null) {
if($id && $toStatus) {
$this->{$this->modelClass}->id = $id;
$data = array($this->modelClass=>array('active'=>$toStatus));
if($this->{$this->modelClass}->save($data, false)) {
$this->Session->setFlash("Record #$id has been $toStatus",'flash_ok');
} else {
$this->Session->setFlash("Record #$id could NOT be $toStatus",'flash_warning');
}
} else {
$this->Session->setFlash('Id or Status not specified','flash_warning');
}
$this->redirect($this->referer());
}

Thanks for your script! I make a little modification in your code and have a little bug, $this->referer is a function. I pass the field to save because we have several flags fields like status, deleted, etc…


function change_status_to($toStatus = null, $id = null, $field = null) {
if( !is_null($id) || !is_null($toStatus) || !is_null($field) ) {
$this->{$this->modelClass}->id = $id;
$data = array($this->modelClass=>array($field => $toStatus));
if($this->{$this->modelClass}->save($data, false)) {
$this->Session->setFlash(”Record has been saved”,’flash_success’);
} else {
$this->Session->setFlash(”Record could NOT be saved”,’flash_info’);
}
} else {
$this->Session->setFlash(’Id or Status not specified’,'flash_failure’);
}
$this->redirect($this->referer());
}

Hi David, thanks for your reply and for pointing out my bug. You’re right about the referer function. I’ve wrapped your code snippet in <code> tags to format it better, hope you don’t mind. I keep meaning to blog about some more of my bake customisations, but haven’t found the time lately. I’ve been focusing too much on learning about Agile and not enough time coding.

I don’t mind that you improve the code, certainly bake customisations can be a whole post. We have an administrator template and with your post we save a lot of time to customize the views after baking

Hey Neil, nice tutorial. I was wondering if you’d be willing to post your code that handles created_by, modified_by etc – that would really help me, as i am quite new to cake, but loving it

Thanks

Hi Daniel,
I’ve written a quick post for you to show you one way of recording created_by and modified_by data in your application.
Hope it helps (and works).

hi
nm11i5pp8t7mkyuy
good luck

Leave a comment