SaveAll for CakePHP (part 3)

Recently i needed to save multiple entries for the same model and i thought saveAll should do the trick.
After trying some different approaches i found the right one. This approach can be used for both new entries and to update entries.

Controller

(/app/controller/tasks_controller.php)

New entry:

function add() {
	if (!empty($this->data)) {
		$this->Task->create();
		if ($this->Task->saveAll($this->data)) {
			$this->Session->setFlash('Tasks saved');
			$this->redirect(array('action'=>'index'), null, true);
		} else {
			$this->Session->setFlash('Tasks could not be saved');
			$this->redirect(array('action'=>'index'), null, true);
		}
	}		
}

Edit entry:

function edit($todo_id=null){
	if (!empty($this->data)) {
		if ($this->Task->saveAll($this->data['Task'])) {
			$this->Session->setFlash('Tasks saved');
			$this->redirect(array('action'=>'index'), null, true);
		} else {
			$this->Session->setFlash('Tasks could not be saved');
			$this->redirect(array('action'=>'index'), null, true);
		}
	} else {
		// Find ten tasks to edit
		$tasks = $this->Task->findAll(null, null, null, 10);
		$this->set('tasks', $tasks);
	}
}

View

For a new entry:

<?php echo $form->create('Task');?>
	<fieldset>
 		<legend><?php __('New Tasks');?></legend>
	<?php
		// Lets generate 10 task input fields
		for(i=0;i<10;i++){
			echo $form->input($i.'.name');
		}
	?>
	</fieldset>
<?php echo $form->end('Submit');?>

To edit entries:

<?php echo $form->create('Task', array('url'=>array('action'=>'edit')));?>
	<fieldset>
 		<legend><?php __('Edit Tasks');?></legend>
	<?php
	
		// Loop trough the ten tasks and create form fields. We need at least the ID to update a task.
		$count = 0;
		foreach($tasks as $task){	
		echo $form->input($count.'.id', array('value'=>$task['Task']['id']));
		echo $form->input($count.'.name', array('value'=>$task['Task']['name']));
		$count++;
	}
	
	?>
	</fieldset>
<?php echo $form->end('Submit');?>

How it works

It’s not much different from the previous saveAll parts, the only really big change is that the form field names are a bit different and you need to specify the right model/array to save in the controller ( the $this->Task->saveAll($this->data['Task']); part).

Filed Under: CakePHP, Code, English - read on

SaveAll with CakePHP (part2)

Since the new beta release for CakePHP there is a nice feature called saveAll and, like the name says, it saves all model data in a form. What this means is that you don’t have to do nasty stuff in the controllers (like looping) and it saves related model data automagically!

Lets make a more advanced todo list to demonstrate.

Tables

Todo hasMany Tasks.

First we need a table named todos.

CREATE TABLE `todos` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) NOT NULL default '',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 ;

We also need a table tasks

CREATE TABLE `tasks` (
  `id` int(11) NOT NULL auto_increment,
  `todo_id` int(11) NOT NULL default '0',
  `name` varchar(255) NOT NULL default '',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 ;

Models

First we create the model todo (in /app/models/todo.php)

<?php
class Todo extends AppModel
{
 var $name = 'Todo';
 var $hasMany = array('Task', array('dependent'=>true));
}
?>

Now we create the model task (in /app/models/task.php)

<?php
class Task extends AppModel
{
 var $name = 'Task';
 var $belongsTo = array('Todo');
}
?>

Controller

Next we set up the tasks controller (in /app/controller/tasks_controller.php)

<?php
class TasksController extends AppController {
	var $name = 'Tasks';
	var $paginate = array('limit' => 50, 'page' => 1);	
	
	function index(){
		$this->set('tasks', $this->paginate('Task'));
	}
	
	function add() {
		if (!empty($this->data)) {
			$this->cleanUpFields();
			$this->Task->create();
			if ($this->Task->saveAll($this->data)) {
				$this->Session->setFlash('List saved');
				$this->redirect(array('action'=>'index'), null, true);
			} else {
				$this->Session->setFlash('List could not be saved');
				$this->redirect(array('action'=>'index'), null, true);
			}
		}		
	}

}
?>

You can see that there is nothing different here except for the $this->Task->saveAll($this->data);
That is where most of the magic happens. The other magic is in the views, lets look at add.ctp

Views

(/app/views/tasks/add.ctp)

<div class="todos form">
<?php echo $form->create('Task');?>
	<fieldset>
 		<legend><?php __('Add Todo');?></legend>
	<?php
		echo $form->input('Todo.name');
	?>
	</fieldset>
	<fieldset>
 		<legend><?php __('Add Tasks for todo');?></legend>
	<?php
		echo $form->input('Task.name');
	?>
	</fieldset>
<?php echo $form->end('Submit');?>
</div>

The result

If you try to save a task with a todo you get the following result:

4	INSERT INTO `todos` (`name`) VALUES ('My todo List')
5	SELECT LAST_INSERT_ID() AS insertID
6	INSERT INTO `tasks` (`todo_id`,`name`) VALUES (135,'My first task')

As you can see, the following happens:

  • The todo gets saved
  • The insert id of the todo is retrieved from the database
  • Now the task gets saved with the todo_id that was just retrieved from the database

The result is a successfully saved model Todo with one task attached to it.

Filed Under: CakePHP, Code, English - read on

SaveAll with CakePHP

SaveAll in Cakephp

Since the new beta release for CakePHP there is a nice feature called saveAll and, like the name says, it saves all model data in a form. What this means is that you don’t have to do nasty stuff in the controllers (like looping).

Lets make a simple todo list to demonstrate.

First we need a table named tasks.
It has an id, int(11) and a name, varchar(255).

Models

Now we set up the model task.php (in /app/models/task.php)

<?php
class Task extends AppModel
{
 var $name = 'Task';
}
?>

Controller

Next we set up the controller (in /app/controller/tasks_controller.php)

<?php
class TasksController extends AppController {
	var $name = 'Tasks';
	var $paginate = array('limit' => 50, 'page' => 1);	
	
	function index(){
		$this->set('tasks', $this->paginate('Task'));
	}
	
	function add() {
		if (!empty($this->data)) {
			$this->cleanUpFields();
			$this->Task->create();
			if ($this->Task->saveAll($this->data)) {
				$this->Session->setFlash('List saved');
				$this->redirect(array('action'=>'index'), null, true);
			} else {
				$this->Session->setFlash('List could not be saved');
				$this->redirect(array('action'=>'index'), null, true);
			}
		}		
	}

}
?>

You can see that there is nothing different here except for the $this->Task->saveAll($this->data);
That is where most of the magic happens. The other magic is in the views, lets look at add.ctp

Views

(/app/views/tasks/add.ctp)

<div class="todos form">
<?php echo $form->create('Task');?>
	<fieldset>
 		<legend><?php __('Add Tasks');?></legend>
	<?php
		echo $form->input('Task.1.name');
                echo $form->input('Task.2.name');
                // and so on...
	?>
	</fieldset>
<?php echo $form->end('Submit');?>
</div>

Note the task.1.name, this is to let the model know that there could be more tasks.
And that’s basically it!

Tomorrow i’ll make a post about the other feature of saveAll, saving related models.

Filed Under: CakePHP, Code, English - read on