Article

The CakePHP Framework: Your First Bite

Page: 1 2 3 4 5 Next

Adding, Editing and Deleting Notes

Next, we'll create a view to add a new note. All we need is a file named add.thtml in the /app/views/notes/ directory:

<h1>Add Note</h1>    
<form action="<?php echo $html->url("/notes/add"); ?>" method="post">    
   
   <p>    
       Title:    
       <?php echo $html->input('Note/title', array('size' => '40'))?>    
   </p>    
   <p>    
       Body:      
       <?php echo $html->textarea('Note/body') ?>    
   </p>    
   <p>    
       <?php echo $html->submit('Save') ?>    
   </p>    
</form>

This code creates a basic form that allows users to enter a title and text for a note, and to save it. This time, I decided to use some convenience code to create the two input tags via the so-called HTML Helper. Helpers will be discussed in detail in the next section of this article, but to be brief, they are classes that are accessible from views, and they contain useful methods for formatting text, creating tags, adding Javascript or AJAX code, and so on. The HTML Helper is available by default in all views, and is used to create (X)HTML tags. I used it in this view to create an input tag, a textarea and a submit button. The syntax is relatively straightforward, but it's important to note that in order to map the input fields to our table columns easily, and thus automate the insertion process, the names of the input fields (usually the first parameter of each method of the HTML Helper) must be in the form <model_name>/<table_field>.

The add method for the Notes Controller can be something like this:

function add()    
   {    
   if (!empty($this->data['Note']))    
       {    
           if($this->Note->save($this->data['Note']))    
           {    
                $this->flash('Your note has been updated.','/notes/');    
           }    
       }    
   }

First of all we check whether or not the $this->data variable -- a sort of "optimized" version of the $_POST array -- is empty. If it contains something, that data is automatically saved in your notes table through the $this->Note->save() method call.

The flash method that's called afterwards will be familiar to anyone who has dabbled in Rails: it's used to keep small amounts of data in between requests, such as error messages or warnings; in this case it displays a temporary message for a few seconds, then redirects the user to http://localhost/notes/.

Note: The created and modified fields of our notes table are automatically populated with relevant data whenever a note is added or modified via the save method, so there's no need to keep track of those actions manually. Pretty useful, hey?

At this point you should notice that something is wrong. The add.thtml view and the add action described above are potentially very, very dangerous in their simplicity: there is no data validation whatsoever, so, at the moment, any kind of data entered by our users will be stored in our database without being filtered or checked. Cake has some built-in validation and input sanitizing mechanisms (which we'll examine briefly in the next section), but we'll keep things simple for now, as this is just a very elementary example to introduce CakePHP's basic features.

Editing a note is similar to adding a new one, the difference being that the edit form's values must already contain data.

/app/views/notes/edit.thtml:    
   
<h1>Edit Note</h1>    
<form action="<?php echo $html->url('/notes/edit')?>" method="post">    
   <?php echo $html->hidden('Note/id'); ?>    
   <p>    
       Title:    
       <?php echo $html->input('Note/title', array('size' => '40'))?>    
   </p>    
   <p>    
       Body:    
       <?php echo $html->textarea('Note/body') ?>    
   </p>    
   <p>    
       <?php echo $html->submit('Save') ?>    
   </p>    
</form>    
   
/app/controllers/notes_controller.php:    
function edit($id = null)    
{    
   if (empty($this->data['Note']))    
   {    
       $this->Note->id = $id;    
       $this->data = $this->Note->read();    
   }    
   else    
   {    
       if($this->Note->save($this->data['Note']))    
       {    
            $this->flash('Your note has been updated.','/notes/');    
       }    
   }    
}

In this case, if no data is submitted, the values from the record we want to edit are retrieved and displayed in the view. Otherwise, if data is submitted, the record is updated via the save method as usual. Again, there are some obvious limitations to this simple function:

  • We do not validate, filter or check the $id parameter (in reality, we should make sure that the $id is numeric and that it actually exists).
  • Submitted data is not validated or filtered.
  • No error handling occurs -- if something goes wrong, the user will never receive a warning message.
  • Finally, in order to delete a note, all we need to do is create a delete action in our NotesController; no view file is necessary, since users will be redirected to the index page, where a message will be displayed.

/app/controllers/notes_controller.php:    
function delete($id)    
   {    
       if ($this->Note->del($id))    
       {    
           $this->flash('The note with id: '.$id.' has been deleted.', '/notes');    
       }    
   }

After defining all of our CRUD operations, we can make the interface easier to use by adding some convenient links for adding, editing and deleting notes. We can also rewrite our index.thtml view using the HTML Helper:

<h1>My Notes</h1>    
<p>    
<?php echo $html->link('Add Note', '/notes/add') ?>    
</p>    
<table>    
   <tr>    
       <th>Id</th>    
       <th>Title</th>    
       <th>Created</th>    
   </tr>    
   <?php foreach ($notes as $note): ?>    
   <tr>    
       <td><?php echo $note['Note']['id']; ?></td>    
       <td>    
     <?php echo $html->link($note['Note']['title'], "/notes/view/{$note['Note']['id']}")?>    
     [<?php echo $html->link('Edit', "/notes/edit/{$note['Note']['id']}")?>,    
     <?php echo $html->link('Delete', "/notes/delete/{$note['Note']['id']}", null, 'Are you sure?')?>]    
       </td>    
   
       <td><?php echo $note['Note']['created']; ?></td>    
   </tr>    
   <?php endforeach; ?>    
</table>

In this example, I used the $html->link() method call, which is able to easily create "Cake-friendly" links. It can take up to six parameters:

  • the text of the link
  • the internal URL
  • an array of HTML attributes (if any)
  • text for a Javascript confirmation message
  • whether we want to convert special characters in the title to HTML entities
  • whether this method should either return or output a value link($title, $url=null, $htmlAttributes=null, $confirmMessage=false, $escapeTitle=true, $return=false)

1540_newindex
The customized index page

The complete controller should look like this:

<?php    
class NotesController extends AppController    
{    
 var $name = 'Notes';    
 function index()    
   {    
         $this->set('notes', $this->Note->findAll());    
   }    
 function view($id)    
   {    
       $this->Note->id = $id;    
       $this->set('data', $this->Note->read());    
   }    
 function add()    
   {    
   if (!empty($this->data['Note']))    
       {    
           if($this->Note->save($this->data['Note']))    
           {    
                $this->flash('Your note has been updated.','/notes/');    
           }    
       }    
   }    
   
 function edit($id = null)    
{    
   if (empty($this->data['Note']))    
   {    
       $this->Note->id = $id;    
       $this->data = $this->Note->read();    
   }    
   else    
   {    
       if($this->Note->save($this->data['Note']))    
       {    
            $this->flash('Your note has been updated.','/notes/');    
       }    
   }    
}    
   
   
 function delete($id)    
   {    
       if ($this->Note->del($id))    
       {    
           $this->flash('The note with id: '.$id.' has been deleted.', '/notes');    
       }    
   }    
}    
?>

Not too difficult, is it? Granted, if you're not accustomed to the MVC pattern, this might all seem a bit strange, but our PHP code definitely looks much more organized and it's much easier to maintain than most unstructured PHP architectures.

One thing to keep in mind is that all those little conventions used in Cake actually matter: for example, the name of the controller must be plural and the model must be singular, while database tables should be plural (CakePHP's Inflector class does the rest), views must be placed in a folder named after the controller, and so on. Yes, you can get around some of these conventions, but it is precisely these details that make Cake virtually self-configuring: it's a case of convention over configuration, exactly like Rails. CakePHP may not be not the best solution for everybody, but it's certainly a simple and intuitive way to solve many of the problems associated with web development.

At this point, you probably have a lot of questions. For example, I wrote that CakePHP has a native validation mechanism and it can sanitize data. What does that mean? Why didn't we modify our model class? We'll answer these and other questions in the next section.

If you liked this article, share the love:
Print-Friendly Version Suggest an Article

Sponsored Links