Creating a CodeIgniter App (Part 4): Users

In part 4 of this series I’ll be showing you how to create the user maintenance for our Simple Task Board app. It will include editing, adding and removing users. Everything will be done using¬†CodeIgniter and I’ll explain the model, controller and views necessary to execute this task. Furthermore, jQuery will be added as well as some CSS.

Introduction

In our last post we finished our login and we started our dashboard, with the menu. It took me some more time to write this post, as I had some problems with attacks to my blog that put it down for a while. Everything is fine now, so let’s get back to the tutorial. Let’s continue with the development of this app by moving into the user maintenance. We will add a couple of methods in our user model (to update and to delete entries). After that we will develop a new controller to handle the user maintenance. Finally, we will also prepare two views to complete the development. To finish up the development, we will use jQuery and add some CSS.

Model

Open the user_model.php file. We’re going to need two additional methods in this model: the update and the delete methods. They will execute the update and removal of users.

    public function update($id, $data)
    {
        if(isset($data['password']))
            $data['password'] = sha1($data['password'].$this->salt);
        $this->db->where('id', $id);
        $update = $this->db->update('user', $data);
        return $update;
    }

The update method will take two parameters – the user ID and an array with the information to be updated. The password (which can be sent in this array if the user chooses to update it) will be concatenated to the salt property and encrypted using the sha1 function, the same way we did when the user is created. The ID will be added to the where condition and the update will be executed for the ‘user’ table. This method will return if the update was successful or not.

    public function delete($id)
    {
        $this->db->where('id', $id);
        $this->db->delete('user');
    }

The other method we need to add into our model is the delete. It is very simple. It takes the ID of the user to be deleted as a parameter and defines the where condition for this ID. After that we execute the delete. That’s all we need inside our model. Now we can go to the controller.

Controller

Create a new controller named user.php. This controller will handle the user maintenance and will have 5 methods plus the constructor.

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class User extends CI_Controller {

    private $LEVEL;

    function User()
    {
        parent::__construct();

        if(!$this->session->userdata('logged'))
            redirect('login');

        $this->LEVEL = array(
            1 => 'Full Access',
            2 => 'Project Manager',
            3 => 'Developer'
        );
    }

}

The constructor will execute the parent constructor and will check if the user is logged in or not (the same way we did in the dashboard controller). Besides that, it will also define the level property, which contains the text for each level. The complete validation of levels has yet to be implemented.

    public function index()
    {
        // Load open transports
        $this->load->model('user_model');
        $data['users'] = $this->user_model->get(false);
        $data['level_list'] = $this->LEVEL;

        $data['page_title']  = "Users";

        // Load View
        $this->template->show('users', $data);
    }

The index method will load all users using the get method from our user_model. The level parameter we defined earlier will be passed as a level_list to our view. Also, the page_title will be defined in this method. Finally, the data array will be sent to the view using the template we created in Part 3.

    public function add()
    {
        $data['page_title']  = "New User";
        $data['email']    = '';
        $data['password'] = '';
        $data['level']    = '1';
        $data['level_list'] = $this->LEVEL;

        $this->template->show('users_add', $data);
    }

    public function edit($id)
    {
        $this->load->model('user_model');
        $data = $this->user_model->get($id);

        $data['password'] = '';
        $data['page_title']  = "Edit User #".$id;

        $data['level_list'] = $this->LEVEL;

        $this->template->show('users_add', $data);
    }

These two methods are similar. add() doesn’t take any parameter – it just defines the default values for email, password and level, as well as the level_list and the page_title (the same way we did for the index method). Then it loads the users_add view (to be created) sending the data array.

The edit method, on the other hand, takes the ID as a parameter. As we are changing an existing user the ID will be used to get this user’s information from the database through the user_model get method. The password will be cleared, so that we don’t send it unnecessarily to the front end. The page_title will have the ID concatenated and the level_list will be sent once again to the view. The data is sent to the same view as before – we will use one view for adding and editing users.

    public function remove($id)
    {
        $this->load->model('user_model');
        $this->user_model->delete($id);

        redirect('user');
    }

The method remove() will take the ID of the user to be removed and will execute the delete method that we have created inside the user_model.

    public function save()
    {
        $this->load->model('user_model');

        $sql_data = array(
            'email'    => $this->input->post('email'),
            'level'    => $this->input->post('level')
        );

        if($this->input->post('reset_password')){
            $sql_data['password'] = $this->input->post('password');
        }

        if ($this->input->post('id'))
            $this->user_model->update($this->input->post('id'),$sql_data);
        else
            $this->user_model->create($sql_data);

        redirect('user');
    }

The last method that we need in this controller is save(). This method will be executed when we save an entry. First thing it does is loading the user_model. Than we get the post values – first we get the email and the user level. Next we check if the user is going to define a new password (in case of new entries this will always be done). If the password should be reset, we also get the post value for the password.

In order to identify if we need to do an update or create a new entry, we check for the ID. If the hidden field with the ID is set, we update the entry. Otherwise we create a new one. In the last line we redirect the user back to the user controller, which will load the index method by default.

If you create an app where the user is only allowed to update his own profile, remember to use the session variable to get the user’s ID. If you use a hidden field like what we will be doing here, the user can change the value of the hidden field and hijack someone else’s profile. In our case, if the user is here he can update the information of all users, so it does not matter.

Now that we have finished our controller we can start our views.

Views

We need two views: users.php and users_add.php. The first will be a list of users and the second will be the form used to add or to edit a user. Create both files and open up users.php.

users.php

<?php
// Load Menu
$this->template->menu('users');
?>

<div id="container">
    <?php if(isset($users)) { ?>
        <table id="users_table" class="board">
            <tr>
                <th class="blue-gradient">ID</th>
                <th class="blue-gradient">Email</th>
                <th class="blue-gradient">Level</th>
                <th class="blue-gradient">Date Created</th>
                <th class="blue-gradient">Actions</th>
            </tr>
        <?php foreach ($users as $user) { ?>
            <tr id="user_<?php echo $user['id']; ?>" class="darker-on-hover">
                <td><?php echo $user['id']; ?></td>
                <td><?php echo $user['email']; ?></td>
                <td><?php echo $level_list[$user['level']]; ?></td>
                <td><?php echo date("j/M/Y, g:i a", strtotime($user['date_created'])); ?></td>
                <td>
                    <?php echo anchor('user/edit/'.$user['id'], '<img src="images/edit.png" title="Edit User"/>'); ?>
                    <?php echo anchor('user/remove/'.$user['id'], '<img src="images/remove.png" title="Remove User"/>', 'class="remove-user-event"'); ?>
                </td>
            </tr>
        <?php } ?>
        </div>
    <?php } ?>
</div>

In the beginning we load the menu template. After showing you the views, we will update this template to show relevant buttons for the user maintenance. After the menu we have a container DIV. If the $users variable was set in the controller, a table will be created. The header is set with ID, Email, Level, Date Created and possible actions. Right after the header we loop through the users and create a TR for each user. The actions are image links to other methods in the controller. In the case of the remove action, there is a class called ‘remove-user-event’, which will trigger a jQuery that opens a popup for confirmation. Later I’ll explain the scripts.

users_add.php

Now open the second view and add the following:

<?php
// Load Menu
$this->template->menu('users');
?>

<div id="container">

    <?php echo form_open('user/save'); ?>

    <table>
        <tr>
            <td>
                <?php echo form_label('Email', 'email'); ?>
            </td>
            <td>
                <?php echo form_input('email', $email); ?>
            </td>
        </tr>
        <tr>
            <td>
                <?php echo form_label('Password', 'password'); ?>
            </td>
            <td>
                <?php if (isset($id)) { ?>
                    <?php echo form_password('password', $password, 'id="password" disabled'); ?>
                    <?php echo form_checkbox('reset_password', 1, false, 'id="reset_password" title="Edit Password"'); ?>
                <?php } else { ?>
                    <?php echo form_password('password', $password, 'id="password"'); ?>
                    <?php echo form_hidden('reset_password', 1); ?>
                <?php } ?>
            </td>
        </tr>
        <tr>
            <td>
                <?php echo form_label('Level', 'level'); ?>
            </td>
            <td>
                <?php echo form_dropdown('level', $level_list, $level); ?>
            </td>
        </tr>
        <tr>
            <td colspan="2">
                <?php if (isset($id)) echo form_hidden('id', $id); ?>
                <div class="form-save-buttons">
                    <?php echo form_submit('save', 'Save', 'class="btn-blue"'); ?>
                    <?php echo form_button('cancel', 'Cancel', 'class="btn-blue" onClick="history.go(-1)"'); ?>
                </div>
            </td>
        </tr>
    </table>

    <?php echo form_close(); ?>

</div>

After the menu we have the same container DIV. Inside this container we have a form with the action ‘user/save’ (user controller, save method) and a table with all fields. The email field is a simple text input. The password field is a password input, but it also have a checkbox next to it. This checkbox will enable the password change – due to the fact that we didn’t sent the password to the front end in the controller, we can’t save it otherwise it will overwrite the original password. In case the user wants to change it, he can tick the checkbox a type the new password. There will be also a JavaScript to enable/disable the input. The last field is the level, which is a dropdown with the values from the $level_list array.

In the last section of our table, we have a hidden ID. It will only be there when the $id variable is set. It will let us know if it is a new user or an update. Then we have a DIV with a ‘form-save-buttons’ class which contains the save and cancel button. The save will submit the form, while the cancel will send the user back in his history. Always remember to close the form using the form_close() function.

There are two things I mentioned that I still need to show to you. The menu template updates and the JavaScript.

Menu Template

Open the menu.php file from the views/template folder.

<div>Simple Task Board</div>
<div id="menu">
    <?php if($view == 'dashboard') { ?>
        <!-- Dashboard menu -->
        <?php echo anchor('user', 'Edit Users', 'class="btn btn_users"'); ?>
    <?php } elseif($view == 'users') { ?>
        <!-- Users menu -->
        <?php echo anchor('dashboard', 'Dashboard', 'class="btn btn_dashboard"'); ?>
        <?php echo anchor('user/add', 'Add new user', 'class="btn btn_add"'); ?>
    <?php } ?>
    <?php echo anchor('login/logout', 'Logout', 'class="btn btn_logout"'); ?>
    <div class="clear"></div>
</div>
<div id="page-title">
    <?php echo $page_title; ?>
</div>

As you can notice now we are differentiating the menu buttons by checking the value of the $view variable. In case we are inside our Dashboard, we will show a button to edit users. In case we are inside the user list, we will see a button to go back to the Dashboard and another one to add a new user.

JavaScript

Create a new folder in the root, named scripts. Inside the new folder create a file called scripts.js. Inside this file add this content:

$(document).ready(function(){
    /* User actions */
    $('#reset_password').click(function(){
        if ($(this).is(':checked')) {
            $('#password').removeAttr('disabled');
        } else {
            $('#password').attr('disabled', true);
        }
    });

    $('.remove-user-event').click(function(){
        var url = $(this).attr('href');
        $('#dialog-confirm').dialog({
            resizable: false,
            height:140,
            modal: true,
            buttons: {
                "Remove": function() {
                    window.location = url;
                },
                Cancel: function() {
                    $( this ).dialog( "close" );
                }
            }
        });

        return false;
    });

});

In this script we have the events for the reset password checkbox and the remove user anchor. This code uses jQuery that we already included in our header. On document ready, the script will attach a click event to the #reset_password element. If it is checked it will remove the disabled attribute of the password input, enabling it. Otherwise it will add the disabled. The script will also attach a click event to the .remove-user-event class. This event will get the HREF attribute and open a dialog with the ID #dialog-confirm. In case the remove is confirmed, the user will be redirected to the HREF attribute (window.location = url). Otherwise the script will just close the dialog.

As we don’t have the #dialog-confirm anywhere, we need to add it. This is a generic DIV for confirming the deletion, so we can use it in different places. Open the footer.php template and update its contents according to this:

<div id="dialog-confirm" style="display:none;" title="Are you sure?">
<p><span></span>This action cannot be undone.</p>
<p>Are you sure?</p>
</div>

</body>
</html>

When the script executes it will show this DIV as the popup. That’s all from a development perspective. Currently the user list looks something like this:

Task Board - Users - No CSS

Task Board – Users – No CSS

CSS

To finish this part of the series, we still need the CSS. But before we get to it, save the following images into your images folder.

Those are the icons we’ll be using in the CSS. Save this files with the same name as they have here, or update them in the CSS and in the HTML. Now, for the CSS, let’s add the menu buttons.

.btn_dashboard{float:left;
background-color:#FFB51B;background-image:url(../images/back.png);
background-image:url(../images/back.png), -webkit-gradient(linear, left top, left bottom, from(#FFD500), to(#FF9C30));
background-image:url(../images/back.png), -webkit-linear-gradient(top,#FFD500,#FF9C30); /* Chrome 10+, Saf5.1+ */
background-image:url(../images/back.png), -moz-linear-gradient(top,#FFD500,#FF9C30); /* FF3.6+ */
background-image:url(../images/back.png), -ms-linear-gradient(top,#FFD500,#FF9C30); /* IE10 */
background-image:url(../images/back.png), -o-linear-gradient(top,#FFD500,#FF9C30); /* Opera 11.10+ */
background-image:url(../images/back.png), linear-gradient(top,#FFD500,#FF9C30)
}
.btn_dashboard:hover{background-color:#FB8F19;background-image:url(../images/back.png);
background-image:url(../images/back.png), -webkit-gradient(linear, 0% 0%, 0% 100%, from(#F78400), to(#FF9C30));
background-image:url(../images/back.png), -webkit-linear-gradient(top,#F78400,#FF9C30); /* Chrome 10+, Saf5.1+ */
background-image:url(../images/back.png), -moz-linear-gradient(top,#F78400,#FF9C30); /* FF3.6+ */
background-image:url(../images/back.png), -ms-linear-gradient(top,#F78400,#FF9C30); /* IE10 */
background-image:url(../images/back.png), -o-linear-gradient(top,#F78400,#FF9C30); /* Opera 11.10+ */
background-image:url(../images/back.png), linear-gradient(top,#F78400,#FF9C30)
}
.btn_users{float:left;
background-color:#FFB51B;background-image:url(../images/user.png);
background-image:url(../images/user.png), -webkit-gradient(linear, left top, left bottom, from(#FFD500), to(#FF9C30));
background-image:url(../images/user.png), -webkit-linear-gradient(top,#FFD500,#FF9C30); /* Chrome 10+, Saf5.1+ */
background-image:url(../images/user.png), -moz-linear-gradient(top,#FFD500,#FF9C30); /* FF3.6+ */
background-image:url(../images/user.png), -ms-linear-gradient(top,#FFD500,#FF9C30); /* IE10 */
background-image:url(../images/user.png), -o-linear-gradient(top,#FFD500,#FF9C30); /* Opera 11.10+ */
background-image:url(../images/user.png), linear-gradient(top,#FFD500,#FF9C30)
}
.btn_users:hover{background-color:#FB8F19;background-image:url(../images/user.png);
background-image:url(../images/user.png), -webkit-gradient(linear, 0% 0%, 0% 100%, from(#F78400), to(#FF9C30));
background-image:url(../images/user.png), -webkit-linear-gradient(top,#F78400,#FF9C30); /* Chrome 10+, Saf5.1+ */
background-image:url(../images/user.png), -moz-linear-gradient(top,#F78400,#FF9C30); /* FF3.6+ */
background-image:url(../images/user.png), -ms-linear-gradient(top,#F78400,#FF9C30); /* IE10 */
background-image:url(../images/user.png), -o-linear-gradient(top,#F78400,#FF9C30); /* Opera 11.10+ */
background-image:url(../images/user.png), linear-gradient(top,#F78400,#FF9C30)
}
.btn_add{float:left;
background-color:#FFB51B;background-image:url(../images/new.png);
background-image:url(../images/new.png), -webkit-gradient(linear, left top, left bottom, from(#FFD500), to(#FF9C30));
background-image:url(../images/new.png), -webkit-linear-gradient(top,#FFD500,#FF9C30); /* Chrome 10+, Saf5.1+ */
background-image:url(../images/new.png), -moz-linear-gradient(top,#FFD500,#FF9C30); /* FF3.6+ */
background-image:url(../images/new.png), -ms-linear-gradient(top,#FFD500,#FF9C30); /* IE10 */
background-image:url(../images/new.png), -o-linear-gradient(top,#FFD500,#FF9C30); /* Opera 11.10+ */
background-image:url(../images/new.png), linear-gradient(top,#FFD500,#FF9C30)
}
.btn_add:hover{background-color:#FB8F19;background-image:url(../images/new.png);
background-image:url(../images/new.png), -webkit-gradient(linear, 0% 0%, 0% 100%, from(#F78400), to(#FF9C30));
background-image:url(../images/new.png), -webkit-linear-gradient(top,#F78400,#FF9C30); /* Chrome 10+, Saf5.1+ */
background-image:url(../images/new.png), -moz-linear-gradient(top,#F78400,#FF9C30); /* FF3.6+ */
background-image:url(../images/new.png), -ms-linear-gradient(top,#F78400,#FF9C30); /* IE10 */
background-image:url(../images/new.png), -o-linear-gradient(top,#F78400,#FF9C30); /* Opera 11.10+ */
background-image:url(../images/new.png), linear-gradient(top,#F78400,#FF9C30)
}

There are 3 buttons that we are adding here. The dashboard, which takes the user back to the Dashboard. The users, which takes the user to the list of users. And the add, which let’s you add an item – for now it is used to add users. All classes follow the same logic as the logout button, co you can paste it right after the .btn_logout:hover definition. The next CSS needs to be added before the CLASSES comment.

/* USERS */
#users_table tr{
text-align: center;
font-size: 12px;
}
#container table {
background-color:#f5f5f5;
border:1px solid #D5D5D5;
margin:0 auto;
}
#container table th{
font-size:14px;
font-weight:normal;
padding:2px;
color:#fff;
text-shadow:1px 1px 0 #3070D5;
border:1px solid #3079ED
}
#container table.board td{
width:25%;
vertical-align:top;
}

This part of the CSS defines the styling for the user list table. It is a little bit generic, because it will also be used for other sections. Now let’s create some styling for the forms. You can paste it right after the last part.

/* FORMS */
label{
margin:4px 5px 0;
}
input,textarea,select,button{
margin:4px 5px 0;
width:400px;
background-color:#fff;
border:1px solid #D5D5D5
}
input:disabled,textarea:disabled,select:disabled,button:disabled{
background: #e9e9e9;
}
input[type=checkbox]{
width:auto;
}
input[type=submit],button{
width:65px;
text-align:center;
margin:4px 5px;
cursor:pointer;
border-radius:5px;
color:#fff;
text-shadow:1px 1px 0 #3070D5;
border:1px solid #3079ED
}
.form-save-buttons{
text-align:center;
}

Something else that needs styling is the jQuery UI dialog. You can put this styling before the CLASSES as well.

/* JQUERY UI DIALOG */
.ui-dialog{
border:1px solid #D5D5D5;
background: #f5f5f5;
padding:2px;
}
.ui-dialog-titlebar{
padding:2px;
background-color:#4A8BF5;
background:-moz-linear-gradient(19% 75% 90deg,#4080E5, #4F8FFF);
background:-webkit-gradient(linear, 0% 0%, 0% 100%, from(#4F8FFF), to(#4080E5));
border:1px solid #3079ED;
}
.ui-dialog-title{
color:#fff;
text-shadow:1px 1px 0 #3070D5;
}
.ui-dialog-titlebar-close{
float:right;
margin-right: 16px;
text-indent: -1000px;
}
.ui-icon-closethick{
background-image: url(../images/close.png);
width:16px;
height:16px;
float:left;
}
.ui-button{
background-color:#4A8BF5;
background:-moz-linear-gradient(19% 75% 90deg,#4080E5, #4F8FFF);
background:-webkit-gradient(linear, 0% 0%, 0% 100%, from(#4F8FFF), to(#4080E5));
}
.ui-dialog-buttonset{
border-top:1px solid #d5d5d5;
padding:2px 0 0;
text-align:center;
}
.ui-icon-alert{
background-image: url(../images/alert.png);
width:16px;
height:16px;
float:left;
margin:10px;
}

Now if you check our app, you’ll see it looks much better.

Task Board - Users

Task Board – Users

Conclusion

If I didn’t forget anything, that’s all for now. In this article we covered everything that was needed to create new users and update existing ones. There are several different ways of implementing this, so I suggest that you try different things. If you do an “open” app, for the general public, I recommend that you use the form_validation library from CodeIgniter. The next posts will be similar in the sense of inserting and updating data from the database.

If you don’t want to create all those files and paste all that information, just download the complete code up to this moment:¬†Task Board Tutorial – Part 4. If you copy this into your existing app, take care not to overwrite the config folder and other things like that (htaccess).



  • thank you OSCAR DIAS, a great tutorial and easy to understand..

  • Abhishek Agarwal

    For the last six month, I was searching for this kind of tut, finally got, thanks OSCAR for your effort you gave to this project. Actually i am feded up with the core coding i wanna work with something new such as CI.