Create a Quick Application in CakePHP: Part 2

Ahsanul Bari

September 2009

Editing a Task

Now that we can add tasks to CakeTooDoo, the next thing that we will be doing is to have the ability to edit tasks. This is necessary because the users should be able to tick on a task when it has been completed. Also, if the users are not happy with the title of the task, they can change it. To have these features in CakeTooDoo, we will need to add another action to our Tasks Controller and also add a view for this action.

Time for Action: Creating the Edit Task Form

  1. Open the file tasks_controller.php and add a new action named edit as shown in the following code:
    function edit($id = null) 
    if (!$id) {
    $this->Session->setFlash('Invalid Task');
    $this->redirect(array('action'=>'index'), null, true);
    if (empty($this->data)) {
    $this->data = $this->Task->find(array('id' => $id));
    } else {
    if ($this->Task->save($this->data)) {
    $this->Session->setFlash('The Task has been saved');
    $this->redirect(array('action'=>'index'), null, true);
    } else {
    $this->Session->setFlash('The Task could not be saved.
    Please, try again.');

  2. Inside the directory /CakeTooDoo/app/views/tasks, create a new file named edit.ctp and add the following code to it:
    <?php echo $form->create('Task');?> 
    <legend>Edit Task</legend>
    echo $form->hidden('id');
    echo $form->input('title');
    echo $form->input('done');
    <?php echo $form->end('Save');?>
  3. We will be accessing the Task Edit Form from the List All Task page. So, let's add a link from the List All Tasks page to the Edit Task page. Open the index.ctp file in /CakeTooDoo/app/views directory, and replace the HTML comment <!-- different actions on tasks will be added here later --> with the following code:
    <?php echo $html->link('Edit', array('action'=>'edit',
    $task['Task']['id'])); ?>
  4. Now open the List All Tasks page in the browser by pointing it to http://localhost/CakeTooDoo/tasks/index and we will see an edit link beside all the tasks. Click on the edit link of the task you want to edit, and this will take you to do the Edit Task form, as shown below:

    Create a Quick Application in CakePHP: Part 2

  5. Now let us add links in the Edit Task Form page to the List All Tasks and Add New Task page. Add the following code to the end of edit.ctp in /CakeTooDoo/app/views:
    <?php echo $html->link('List All Tasks', array('action'=>'index')); ?><br />
    <?php echo $html->link('Add Task', array('action'=>'add')); ?>

What Just Happened?

We added a new action named edit in the Tasks controller. Then we went on to add the view file edit.ctp for this action. Lastly, we linked the other pages to the Edit Task page using the HTML helper.

When accessing this page, we need to tell the action which task we are interested to edit. This is done by passing the task id in the URL. So, if we want to edit the task with the id of 2, we need to point our browser to http://localhost/CakeTooDoo/tasks/edit/2. When such a request is made, Cake forwards this request to the Tasks controller's edit action, and passes the value of the id to the first parameter of the edit action. If we check the edit action, we will notice that it accepts a parameter named $id. The task id passed in the URL is stored in this parameter.

When a request is made to the edit action, the first thing that it does is to check if any id has been supplied or not. To let users edit a task, it needs to know which task the user wants to edit. It cannot continue if there is no id supplied. So, if $id is undefined, it stores an error message to the session and redirects to the index action that will show the list of current tasks along with the error message.

If $id is defined, the edit action then checks whether there is any data stored in $this->data. If no data is stored in $this->data, it means that the user has not yet edited. And so, the desired task is fetched from the Task model, and stored in $this->data in the line: $this->data = $this->Task->find(array('id' => $id)); Once that is done, the view of the edit action is then rendered, displaying the task information. The view fetches the task information to be displayed from $this->data.

The view of the edit action is very similar to that of the add action with a single difference. It has an extra line with echo $form->hidden('id');. This creates an HTML hidden input with the value of the task id that is being edited.

Once the user edits the task and clicks on the Save button, the edited data is resent to the edit action and saved in $this->data. Having data in $this->data confirms that the user has edited and submitted the changed data. Thus, if $this->data is not empty, the edit action then tries to save the data by calling the Task Model's save() function: $this->Task->save($this->data). This is the same function that we used to add a new task in the add action.

You may ask how does the save() function of model knows when to add a new record and when to edit an existing one? If the form data has a hidden id field, the function knows that it needs to edit an existing record with that id. If no id field is found, the function adds a new record.

Once the data has been successfully updated, a success message is stored in the session and it redirects to the index action. Of course the index page will show the success message.

Adding Data Validation

If you have come this far, by now you should have a working CakeTooDoo. It has the ability to add a task, list all the tasks with their statuses, and edit a task to change its status and title. But, we are still not happy with it. We want the CakeTooDoo to be a quality application, and making a quality application with CakePHP is as easy as eating a cake.

A very important aspect of any web application (or software in general), is to make sure that the users do not enter inputs that are invalid. For example, suppose a user mistakenly adds a task with an empty title, this is not desirable because without a title we cannot identify a task. We would want our application to check whether the user enters title. If they do not enter a title, CakeTooDoo should not allow the user to add or edit a task, and should show the user a message stating the problem. Adding these checks is what we call Data Validation. No matter how big or small our applications are, it is very important that we have proper data validation in place. But adding data validation can be a painful and time consuming task. This is especially true, if we have a complex application with lots of forms.

Thankfully, CakePHP comes with a built-in data validation feature that can really make our lives much easier.

Time for Action: Adding Data Validation to Check for Empty Title

  1. In the Task model that we created in /CakeTooDoo/app/models, add the following code inside the Task Model class. The Task Model will look like this:
    class Task extends AppModel {
    var $name = 'Task';
    var $validate = array(
    'title' => array( 'rule' => VALID_NOT_EMPTY,
    'message' => 'Title of a task cannot be empty' )

  2. Now open the Add Task form in the browser by pointing it to http://localhost/CakeTooDoo/tasks/add, and try to add a task with an empty title. It will show the following error message:

    Create a Quick Application in CakePHP: Part 2

What Just Happened?

We added an array named $validate in the Task Model class. All validation related to the data in a model should be defined in this array. We then defined an index named title. Every database field that we want to validate should have an index defined in $validate. As we want to validate the title field of the tasks table, we declared an index with the same name.

The title index also points to an array that contains two more indices named rule and message. The rule index should point to a built-in validation rule. In this case, we do not want the title to be empty, so the rule that checks this is VALID_NOT_EMPTY. There are many more useful built-in rules defined in CakePHP. The message index should point to the error message that we want to show when users fail to follow the defined rule.

Now, whenever a user adds or edits the title of a task, CakePHP will check the defined rules.

Deleting a Task from CakeTooDoo

CakeTooDoo can now list all tasks, add new tasks, and edit tasks as well. The only thing that is remaining is the ability to delete a task.

As usual, we will need to add an action to the Task controller. But, unlike other actions, the delete action will not require a view. We will just add a link to the task actions named delete. When clicked it will show a JavaScript confirm dialogue. And once we confirm, the selected task will be deleted.

Time for Action: Adding Data Validation

  1. Open the file tasks_controller.php and add a new action named delete as shown in the following code:
    function delete($id = null) 
    { if (!$id) {
    $this->Session->setFlash('Invalid id for Task');
    $this->redirect(array('action'=>'index'), null, true);
    if ($this->Task->del($id)) {
    $this->Session->setFlash('Task #'.$id.' deleted');
    $this->redirect(array('action'=>'index'), null, true);
  2. We will be deleting task from the List All Task page. So, let's add a link from the List All Tasks page to delete a task. Open the index.ctp file in /CakeTooDoo/app/views directory, and place the following code below the Edit link we placed earlier:
  3. Open the View All Tasks page from the browser by pointing it to http://localhost/CakeTooDoo/tasks/index. We will notice a Delete link beside all the tasks. Try deleting a task by clicking on this link
    <?php echo $html->link('List Done Tasks', array('action'=>
    'index', 'done')); ?><br />
    <?php echo $html->link('List Pending Tasks', array('action'=>
    'index', 'pending')); ?><br />

What Just Happened?

As already mentioned, the delete action will be accessed through the link in the task actions in the list page. For that we added a HTML link using the HTML helper's link() function. The argument passed to the link() function is the title of the link, in this case, it is Delete. The second argument is an array that declares the action we want to point. In this case, it is the delete action that we just created. Since the delete action needs to know the task that we want to delete, we also sent the task id in this array. The third argument is null and does not need to be used for the time being. In the fourth argument, we pass the message that should be shown in the JavaScript confirmation dialogue. In this case, we would like to ask the user whether they are sure that they want to delete this task.

Once the user confirms that they want to delete the task, a request is made to the delete action of the task controller. The id of the task that we want to delete is stored in the first parameter of the delete action that we named $id.

If $id is empty, the delete action does not know which task to delete. So, an error message is stored in the session and the page is redirected to the index action.

If an id is present, the del() function of the Task model is called, which actually deletes the task. After successfully deleting the task, the delete action stores a success message into the session and redirects to the index page. Once in the index page, the success message is displayed along with the list of tasks.

Viewing Completed Tasks and Pending Tasks

CakeTooDoo can already list all the tasks that are stored in its database. But as we use it, there will be some tasks that are completed, and some that are still pending. We would like CakeTooDoo to have the ability to list the completed and pending tasks separately. This will allow us to see more clearly which tasks are completed and which are still hanging around.

As you will see, we will not add separate actions for these lists. In fact, we will just modify the index action so that it displays different lists. This will be achieved by passing a parameter to the index action that will tell what list the user wants to see.

Time for Action: Viewing Completed and Pending Tasks

  1. Open the file tasks_controller.php and replace the code of the index action with this one:
    function index($status=null) {
    if($status == 'done')
    $tasks = $this->Task->find('all', array('conditions' =>
    array('Task.done' => '1')));
    else if($status == 'pending') $tasks = $this->Task->find('all',
    array('conditions'=>array('Task.done' => '0')));
    else $tasks = $this->Task->find('all');
    $this->set('tasks', $tasks);
    $this->set('status', $status);
  2. To access the Completed and Pending Task Lists from the List All Tasks Page, add the following code to the end of index.ctp file in the /CakeTooDoo/apps/views directory:
    <?php if($status): ?> 
    <?php echo $html->link('List All Tasks', array('action'=>'index')); ?><br />
    <?php endif;?>
    <?php if($status != 'done'): ?>
    <?php echo $html->link('List Done Tasks', array('action'=>'index', 'done')); ?>
    <br />
    <?php endif;?>
    <?php if($status != 'pending'): ?>
    <?php echo $html->link('List Pending Tasks', array('action'=>
    'index', 'pending')); ?><br />
    <?php endif;?>

  3. To access the Completed and Pending Task Lists from the Add New Task and the Edit Task pages, add the following code to the end of the files add.ctp and edit.ctp in /CakeTooDoo/apps/views directory:

What Just Happened?

We modified the index action by adding some new codes. The first thing that we did is to add a parameter named $status to the index action. If $status = 'done', then it calls the find() function of the Task model with a condition: $this->Task->find('all', array('conditions' => array('Task.done' => '1'))). Here, we tell the Task model to return only those tasks that have the field done equal to 1. Any task that has been completed will have done equal to 1. Or if it is still pending, it will have a done field with the value of 0. If $status = 'pending', then it will return only those tasks that have a done field value of 0. Lastly, if $status is undefined, it will return all the tasks present in the tasks table.

All the tasks data returned from either of the three find() calls are stored in a local variable named $tasks. This is sent to the view by calling the set() function of the controller. The status of the tasks sent to the view is also sent to the view.

In the view, we then added separate links to completed tasks and pending tasks. We do not want to show the link to the current page. For example, if we are in the list of all completed tasks, we do not want this page to have a link to the completed tasks. For this, we did a simple check using the $status variable sent to the view.

Formatting Date and Time

When we list tasks, you may have noticed that the time of task creation and modification are quite unreadable for a normal user. We would like this to be in a nicer format, so that the user can quickly understand when the task was added or last modified. For this, we will be using another built-in Helper of CakePHP: the Time Helper.

Time for Action: Formatting the Created and Modified Time

  1. Add the Time Helper to the tasks controller, by adding Time at the end of the $helper array in tasks_controller.php:
    var $helpers = array('Html', 'Form', 'Time');
  2. Open the file index.ctp in /CakeTooDoo/app/views/tasks and replace the code <?php echo $task['Task']['created'] ?> with the following:
    <?php echo $time->niceShort($task['Task']['created']) ?>
  3. In the same file, replace the code <?php echo $task['Task']['modified'] ?> with the following:
    <?php echo $time->niceShort($task['Task']['modified']) ?>


What Just Happened?

Here, we just added another helper to the Tasks controller called the Time Helper. The Time Helper is a built-in helper of CakePHP that has functions to help display time and date related data. We then used a function named niceShort() of the Time Helper and passed it the creation and modification times to display them in a nicer format. Check the following screenshot:

Create a Quick Application in CakePHP: Part 2

Creating the CakeTooDoo Homepage

We are almost done. Just to make the features of CakeTooDoo more accessible and easier to follow, we will be creating a homepage. This homepage will introduce the users to all the features of CakeTooDoo, and allow them to access all the other pages quickly.

The homepage does not need any logic, as it is only a static page. So far, all the pages that we created had a corresponding action and a view. As the homepage does not need any control logic, it does not make sense to have a controller action for it.

For pages that do not need any controller action, Cake has a controller called pages. We simply need to add a view for the page, and the page will be viewed. There is no need to add any controller action.

Time for Action: CakeTooDoo Homepage

  1. Move into the directory /CakeTooDoo/app/views/pages directory, and create a file named home.ctp.
  2. In the file home.ctp, we just created, write the following code:
    <h1>Welcome to CakeTooDoo</h1>
    <p>CakeTooDoo is a simple but useful application to keep a record
    of all the things that you need to do. Using CakeTooDoo, you can:</p>
    <li><?php echo $html->link('List all your tasks',
    array('controller' => 'tasks', 'action'=>'index')); ?></li>
    <li><?php echo $html->link('List your completed tasks',
    array('controller' => 'tasks', 'action'=>'index','done'));
    <li><?php echo $html->link('List your pending tasks',
    array('controller' => 'tasks', 'action'=>'index',
    'pending')); ?></li>
    <li><?php echo $html->link('Add new Tasks', array('controller'
    => 'tasks', 'action'=>'add')); ?></li>
    <li>Edit tasks</li>
    <li>Delete tasks</li>
  3. Now point the browser to http://localhost/CakeTooDoo/ to view the CakeTooDoo homepage.

What Just Happened?

We created a view file named home.ctp that highlights the features of CakeTooDoo and links to all the pages in CakeTooDoo. As we do not need any controller for this page, we placed the file in the pages directory found in the views directory.

Any page that does not have any controller action should be placed in the pages directory. To access these pages, we have to point the browser to a URL like this: http://localhost/CakeTooDoo/pages/<view file name>. For the homepage, we just created, the URL that we need to call is: http://localhost/CakeTooDoo/pages/home.

But you will have noticed that when we open the URL: http://localhost/CakeTooDoo/, it shows the homepage. This is because Cake makes the home.ctp view in the pages directory the default page of the application. So whenever the application is called without any controller and action name, Cake directs the browser to the default homepage (/views/pages/home.ctp). Here's how the new homepage of CakeTooDoo will look:

Create a Quick Application in CakePHP: Part 2


This article was a quick roller coaster ride through the important aspects of CakePHP. We saw how we can create an application that we called CakeTooDoo. It can manage to-do lists, list all the tasks, add tasks, edit tasks, and delete tasks. And it can also do a few more cool stuffs.

This article showed how we can create a database that follows the Cake convention, and to configure Cake to use it. It also discussed how to create a model, a controller, and views, and the conventions that we need to follow to make them work together.

In this article, we learned a few important model functions like find(), create(), save(), and del(). We also saw the use of controller functions like set() and redirect(). The HTML Form and the Time Helper was also introduced, and we saw how the functions of these helpers can make it easier to display views.

Then, we briefly saw the use of the built-in data validation of Cake. Lastly, we also saw the use of the pages controller that allows the creation of views without controller actions.

Most importantly, this article showed us that making a quality and structured web application with Cake is truly a "piece of cake"!


If you have read this article you may be interested to view :

You've been reading an excerpt of:

CakePHP Application Development

Explore Title