Refactoring CakePHP baked views and controllers

Posted by Matt on Tue, Jan 01 2008

This post is part 1 of a series focusing on CakePHP 1.2.

CakePHP's Interactive Bake Shell is one it's most powerful features. It is a simplified command line interface for code generation. Most commonly it is used to generated code for models, views or controllers. I often use it to create a base of code, then tweak that code to fit into the application. An obvious issue is the baked code has actions and views for both add and edit functionality. Very often these two operations are virtually identical so, it doesn't really make sense maintaining separate code that does the same thing, commonly know as DRY.

Merging the add and edit actions

This is actually quite simple and only take a minute to do. The steps are the same for both the regular add/edit and the admin routed add/edits.

The Add Action

Open the generated controller PHP file. In it you'll see a function for add() and another for edit(). Replace the entire add function with a call to render the edit view. It should look like this:

	function add() {
		$this->render('edit');
	}

You could also completely remove this action and fix any link that point to /controller/add to /controller/edit, but I prefer this way, since code generated for other models may have links to this model if the tables are related. You can delete the /views/controller/add.ctp file.

The Edit Action

There are a few more changes required in the edit action. Find the edit function, right below the add function. Delete the first if statement:

		if (!$id && empty($this->data)) {
			$this->Session->setFlash('Invalid Model');
			$this->redirect(array('action'=>'index'), null, true);
		}

Further down these is:

if (empty($this->data)) {

Change that to read:

if ($id && empty($this->data)) {

The Edit View

As I mentioned above you can delete the add view (add.ctp). In the edit view (edit.ctp) you'll need to add a parameter to the form create line to make sure the form always submits to the edit action. It should like something like this (your model will vary):

<?php echo $form->create('Model', array('url' => array('action' => 'edit'))); ?>

You may also want to change the legend so that it reflects whether you are adding or editing the record. There are a couple different ways to do this, but the quickest is to check the action:

<?php echo sprintf(__('%s %s', true), __(ucwords($this->action), true), __('Model', true));?>

That's it. You now have an action and view that handles both add and edits.

Posted in CakePHP

3 Comments

Silver Knight said on Aug 19, 2008
Hey, thanks much for this post. I was just looking for how to do this very thing the other day and found some basics on the topic, but this post is much more detailed and complete. Really helped me clean things up quite a bit.
BATIGA said on May 13, 2009
This is really usefull. how ever using $this->render('edit'); has a drawback. You won't be able to set the values for your select boxes and the others components that require preloading the data.

so i use $this->redirect instead of render. Then when i'll be done with the coding, and i'm sure that all my controller can use either add or edit, i'll create a route to redirect all add actions to edit actions.
Matt said on May 13, 2009
Hey BATIGA,
I've now started deleting the add action altogether and using a route to have add calls load the edit action:

Router::connect('/:controller/add', array('action' => 'edit'));