Ruben Tan has severe brain damage after constantly hitting himself whenever he faces problems in his programming projects, and thus have a weird outlook on life which prevents him from being trapped in the surface of lies.

After developing on Codeigniter for some time, I’ve developed some personal best practices that I believe I should list them down here. Codeigniter has a fairly “loose” MVC framework, giving you great liberty as to how to structure your system (I’ve even tried changing its MVC model into a more PAC oriented one…), and thus it is important that one develop a set of standard coding practices in Codeigniter to improve your application’s maintainability.

Before we start, let’s define the three logics that we’ll be talking about today - application logic, presentation logic, and business/data logic. Application logic refers to how your application works independently of presentation and business logic, which can be how your app fetches data from various sources, sets timestamps, modify configuration files and so forth. Presentation logic refers to how your app should display the datasets to the user, while business/data logic deals with how your app fulfills the business requirement.

Application logic

In a conventional MVC structure, Model handles the business/data logic, View handles the presentation logic, while Controller stitches them together. Application logic is sometimes delegated to third-party classes such as libraries or helpers, while some developers prefer to put them into Models.

There’s nothing wrong with these approaches, but personally I like something that is more institutionalized, and thus I strongly enforce myself to put these application logic into the Controller itself. In a way, the controller becomes the heaviest component of the three.

Let’s do this with an example - a simple blog.

The actions possible are:

  • Add new post
  • Edit post
  • Delete post
  • List all posts
  • View single post

Thus in the controller, we’d have these functions:

  • newpost()
  • editpost($id)
  • deletepost($id)
  • listposts($column, $order, $offset, $limit)
  • viewpost($id)

In the model, we’ll have something like:

  • newpost($input)
  • editpost($input)
  • deletepost($id)
  • getpost($id)
  • getposts($column, $order, $limit, $offset)

Now you’ll find this structure fairly consistently used throughout most conventional webapps. My previous pet project’s entire admin control consists of exact duplicates of these functions for all different functionalities and entities in the control panel, so you’ll want to build some sort of a standard coding practice around this structure.

In this article, I’ll deal ONLY with Controllers, and specifically, the application logic of three controller functions - new post and edit post.

Redirect vs load view

Before we move on, we’ll need to define one more thing - when to use redirects and when to use views. As a general rule of thumb:

  • Use redirects when an operation has concluded
  • Use views at the end of an operation

Confusing? Well, here’s an example. Assuming you want to edit a post. “Edit post” is an operation in itself, which has a general flow like this:

  • edit post controller function called
  • edit post view showed
  • user clicks on submit button
  • edit post controller function called
  • edit post model function called and parameters passed in
  • if not successful, show edit post view with error message
  • repeat step 3 if not successful
  • if successful, go to dashboard

In this operation flow, redirect is only used at the VERY END of the operation AFTER it has been concluded, which in this case, is step 6. Load view, on the other hand, is used at the END of individual steps, like in step 2 and step 6.

The reasoning is because loading views does not change your URL, which redirecting does. If you do not perform a redirect in Step 8, you will see that the URL has not changed AND the post variables are still accessible, which might be a security concern in some applications.

Therefore always be clear to use redirect when the operation has concluded successfully instead of just loading views.

New Post

In the new post function, it is fairly straightforward. In most applications you’ll have at least (1) a template engine, (2) a custom validation engine capable of setting default values, and (3) a security model. For the sake of simplicity, we’ll leave out the security model for now.

The basic logic flow of this function should look like this:

  • set various template variables (get menu, define active tab, etc)
  • setup validation class (configuration and rules)
  • load any other misc. information like category list
  • if validation == FALSE
    • load newpost view
  • else
    • save item (call model)
    • if save successful
      • set flash message - success message
      • redirect to listposts or frontpage
    • else
      • set flash message - failure message / error messages
      • load newpost view

Edit Post

Edit post’s logic flow is quite similar to new post, with a couple of differences. Firstly, when it pulls up the edit view, it’ll need to have default values already in the form, and when the user submits the form, it’ll have to call the same function BUT instead of pulling up default values, it should call the model to save the form. Sounds complex?

Let’s break them down. The typical operation flow of an edit post goes like this:

  • set various template variables (get menu, define active tab, etc)
  • setup validation class (configuration and rules)
  • if can’t get item, redirect to dashboard with error message
  • try to get the hidden id post data from the form (if it exists, it means the user is trying to save the item. otherwise, the user is merely trying to access the edit page)
  • if hidden id exists, id = hidden id value
  • get the item using the id parameter
  • if hidden id does NOT exists, load default values
  • if validation == FALSE
    • load editpost view
  • else
    • save item
    • if save successful
      • set flash message - success message
      • redirect to listposts or frontpage
    • else
      • set flash message - failure message / error messages
      • load editpost view

Sounds a bit confusing? Here’s some sample code just in case you get lost:


public function editpost($id = 0) {
//set various template variables
//...
//setup validation class
//...
//get hiddenid
$hiddenid = $this->input->post('id');
//if hidden id exists, then set the id as hiddenid
if($hiddenid != null) $id = $hiddenid;
//prevents the user from directly calling the editpost
if($id == 0) redirect('management/dashboard');
//get the item using the id parameter
$this->load->model('Post_model');
$item = $this->Post_model->get_item($id);
if($item == null) redirect('management/dashboard');
//set the default values
if($hiddenid == null) $this->validation->set_default_values($item);
//validation logic
if($this->validation->validate() == FALSE)
{
$this->load->view('editpost.view.php');
}
else
{
$msg = $this->Post_model->edit_story($input);
if($msg == '')
{
$this->session->set_flashmessage('msg', 'Success!');
redirect('management/listposts');
}
else
{
$this->load->view('editpost.view.php', array('msg' => $msg));
}
}
}

A bit better? I certainly hope so.

Conclusion and future updates

I will update this article in case of any errors, and if I do make any mistakes with the code or the logic, please don’t hesitate to comment below.

Again I would need to re-iterate that Codeigniter is a loose system, and like all flexible systems it allows you great leniency in determining how you want your application logic to work. By establishing a standard code of practice on the MVC model, you stand to create a system that is well-documented and easy to maintain in the future, and this is essential for projects that are worked on by more than just one person.

Check back for updates!

Edit:

11 Aug 2008 - Fixed a logic flaw in the code on setting the flash message (credit: TJ)

6 Responses to “Codeigniter Best Practices - Controller”

  1. Why you set session flash when $msg == ” ? It’s empty. Right?

    if($msg == ”)
    {
    $this->session->set_flashmessage(’msg’, $msg);
    redirect(’management/listposts’);

    TJ

  2. Opps, the $msg in the flash message should be an actual message in string (e.g. ‘file saved successfully’ or ‘edited file successfully’).

    Thanks for the correction.

    admin

  3. This blog is awesome!

    vilhelmotelfairhoneygrove

  4. Hey, I was searching blogs, and came onto yours, and I like it.

    holbechonabt36

  5. Great information on your blog!

    kaynardtblackshear

  6. Hey, you have a great blog here! I’m definitely going to bookmark you!

    he0131

Leave a Reply