Well… Even though I get a lot of thanks for what I’ve wrote so far (and even some correction on some faulty code… I’m only human…), there are still people who don’t know how to handle an edit method. So I thought “why not get back to the basics?”.
So how about an “edit page”? An “edit page” is a page that allows you to edit a row of data taken from the database.
Usually, when someone wants to edit something, he is taken to a method named edit(). This method would receive a parameter that represents the id of the element we want to edit. So let’s start by creating it the basic controller.
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Welcome extends CI_Controller { public function index() { echo 'hello'; } public function edit($id) { } }
We first need to make sure that the id passed to the method is an integer. So how do we do this? We have two options: we either choose to use a php function to validate the id or use the form validation methods offered by the CodeIgniter:
1. use a PHP function:
if(is_numeric($id)===FALSE || $id==0) { redirect('welcome'); }
2. Call the validation rule as a discreet function. To do this we first should make sure that the form validation library is loaded:
if($this->form_validation->is_natural_no_zero($id)===FALSE) { redirect('welcome'); }
For the sake of this tutorial we will keep it inside CodeIgniter, so let’s see the controller again by using the second way of validating the id:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Welcome extends CI_Controller { public function index() { echo 'hello'; } public function edit($id) { $this->load->library('form_validation'); if($this->form_validation->is_natural_no_zero($id)===FALSE) { redirect('welcome'); } } }
For the tutorial to be as short as it can be, we will assume that the row of data will contain only an id and a title field. So once we have the id we must retrieve the data from the database. Also, for brevity (and to promote MY_Model…) we will use my MY_Model that will allow us to use fast access to the data. So download MY_Model.php from my github repo (which can be found inside the core directory) and put it inside your application/core directory):
Now, we need to create a model for our needs. Let’s assume we work with a “posts” table. So we create a Post_model.php inside application/models.
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Post_model extends MY_Model { public $table = 'posts'; public $primary_key = 'id'; public $timestamps = FALSE; public function __construct() { parent::__construct(); } }
After this we may as well forget about the model and return to our controller:
$this->load->model('post_model'); $post = $this->post_model->get($id);
As you can see, due to the fact that the model extends MY_Model, we can retrieve the post fast by using a get() method that we pass the id (take a note that the get() method does not belong to the CI_Model in this example, but to our MY_Model). Now that we have the post requested by the id, we pass the data to our edit form (without forgetting to load the form helper):
$data['post'] = $post;
And we load the view passing it the data:
$this->load->view('edit_view',$data);
Let’s see the controller again:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Welcome extends CI_Controller { public function index() { echo 'hello'; } public function edit($id) { $this->load->library('form_validation'); if($this->form_validation->is_natural_no_zero($id)===FALSE) { redirect('welcome'); } $this->load->model('post_model'); $post = $this->post_model->get($id); $data['post'] = $post; $this->load->helper('form'); $this->load->view('edit_view',$data); } }
Oups… our first potential error… What if the post doesn’t exist? What if the user wants to edit a post that has an id that doesn’t exist? We need to make sure we have a post, or else redirect to the index() method:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Welcome extends CI_Controller { public function index() { echo 'hello'; } public function edit($id) { $this->load->library('form_validation'); if($this->form_validation->is_natural_no_zero($id)===FALSE) { redirect('welcome'); } $this->load->model('post_model'); $post = $this->post_model->get($id); if($post===FALSE) { redirect('welcome'); } $data['post'] = $post; $this->load->helper('form'); $this->load->view('edit_view',$data); } }
Let’s create the form, namely a file named edit_view.php that we will place inside the application/views directory.
echo form_open(); echo form_label('title','Title'); echo form_input('title',set_value('title',$post->title).'<br />'; echo form_submit('submit','Edit'); echo form_close();
Well… this is a bare-bone form… Let’s also add the error messages… who knows…
echo form_open(); echo form_label('title','Title'); echo form_error('title'); echo form_input('title',set_value('title',$post->title).'<br />'; echo form_submit('submit','Edit'); echo form_close();
Someone may notice that we didn’t pass the id of the post inside a hidden input, but I ask you: “Why? Why would we need to pass this id to the form?”. Because we already have taken the id from the url of the page, we already verified is an integer, and we already verified that the id is a valid one. This is why we really do not need to pass the id to the form. If some user want so look smart by changing the id in the url, it’s his problem, not yours, because I suppose he already passed a login system and got to the form having the right credentials. If the id doesn’t exist, the user will already be redirected to the index() method and wouldn’t manage to arrive at the form.
Now we save the edit_view.php and, if we try the page on our browser with a valid id we should see the pre-filled form with data taken from the database. But this is not over yet. We need to validate the data and, if validation is successful, we need to save the data back to the database. So let’s return to our controller and do the validation:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Welcome extends CI_Controller { public function index() { echo 'hello'; } public function edit($id) { $this->load->library('form_validation'); if($this->form_validation->is_natural_no_zero($id)===FALSE) { redirect('welcome'); } //LET'S ESTABLISH THE VALIDATION RULES FIRST... $this->form_validation->set_rules('title','Title','trim|required'); //NOW WE VERIFY IF SOMEONE HAS ARRIVED HERE AS A RESULT OF FILLING THE FORM OR BY VISITING THE URL, SIMPLY BY DOING THE VALIDATION OF A POTENTIAL FORM if($this->form_validation->run()===FALSE) { //AS YOU CAN SEE, IF SOMEONE COPLETED THE FORM POORLY (WITHOUT TITLE IN THIS CASE, WHICH IS REQUIRED) OR ARRIVED AT THE PAGE BY URL, THEY WILL RECEIVE THE FORM VIEW $this->load->model('post_model'); $post = $this->post_model->get($id); if($post===FALSE) { redirect('welcome'); } $data['post'] = $post; $this->load->helper('form'); $this->load->view('edit_view',$data); } else { echo 'form completed correctly'; } } }
Now, when we visit our page, if we fill the form with new values (or even if we let the form as is and submit it), we should be getting a “form completed correctly”. Cool.
So… our visitor managed to get the the else {…} part. Let’s update the table with the new values and redirect the visitor to the index() method:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Welcome extends CI_Controller { public function index() { echo 'hello'; } public function edit($id) { $this->load->library('form_validation'); if($this->form_validation->is_natural_no_zero($id)===FALSE) { redirect('welcome'); } //LET'S ESTABLISH THE VALIDATION RULES FIRST... $this->form_validation->set_rules('title','Title','trim|required'); //NOW WE VERIFY IF SOMEONE HAS ARRIVED HERE AS A RESULT OF FILLING THE FORM OR BY VISITING THE URL, SIMPLY BY DOING THE VALIDATION OF A POTENTIAL FORM if($this->form_validation->run()===FALSE) { //AS YOU CAN SEE, IF SOMEONE COPLETED THE FORM POORLY (WITHOUT TITLE IN THIS CASE, WHICH IS REQUIRED) OR ARRIVED AT THE PAGE BY URL, THEY WILL RECEIVE THE FORM VIEW $this->load->model('post_model'); $post = $this->post_model->get($id); if($post===FALSE) { redirect('welcome'); } $data['post'] = $post; $this->load->helper('form'); $this->load->view('edit_view',$data); } else { $title = $this->input->post('title'); // we already have the ID, so we actually do not need to get the input hidden value, because that one is passed in the url. I think this is the perfect way of working with the id, as you already verified if the id is correct. $updated_data = array( 'title' => $title ); //now we simply update the data //TAKE NOTE: THE UPDATE() METHOD IS DEFINED IN THE MY_Model FILE. if($this->post_model->update($updated_data,$id)) { redirect('welcome'); //of course you can also pass a success message inside a session variable (maybe a flash type of message?) } else { echo 'Couldn\'t update the data'; exit(); } } } }
And that’s all!
“TOO MUCH FOR A SIMPLE UPDATE!”, you might say… Well… we can also use our MY_Model, which has a from_form() method available. So how would we go…
Using MY_Model to update data from a form
To validate the form we first need to move the validation rules inside the Post_model.php. So how would the model look?
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Post_model extends MY_Model { public $table = 'posts'; public $primary_key = 'id'; public $timestamps = FALSE; public function __construct() { parent::__construct(); } public $rules = array( 'insert' => array( 'title' => array('field'=>'title', 'label'=>'Title', 'rules'=>'trim|required') ), 'update' => array( 'title' => array('field'=>'title', 'label'=>'Title', 'rules'=>'trim|required') ) ); }
Now returning to our controller we would change it like so:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Welcome extends CI_Controller { public function index() { echo 'hello'; } public function edit($id) { $this->load->library('form_validation'); if($this->form_validation->is_natural_no_zero($id)===FALSE) { redirect('welcome'); } $this->load->model('post_model'); $post = $this->post_model->get($id); //WE FIRST NEED TO VERIFY IF THERE IS A POST WITH THE ID PASSED IN THE URL. IF THERE IS ONE WE NEED TO SEE IF THE UPDATE WAS DONE. MY_MODEL WILL SEE IF THERE WAS A FORM SUBMITED OR NOT AND WILL VERIFY IF THE FORM WAS FILLED CORRECTLY. IF EVERYTHING WAS DONE, MY_MODEL WILL UPDATE THE ROW AND IF THE UPDATE WAS DONE WILL RETURN THE ID OR FALSE IF IT WASN'T. if($post===FALSE || $this->post_model->from_form(NULL,array('id'=>$id),array('id'))->update()===FALSE) { $data['post'] = $post; $this->load->helper('form'); $this->load->view('edit_view',$data); } else { echo 'Couldn\'t update the data'; } } }
Well… that from_form() is a really ugly method… What are those parameters??? I needed to read my own documentation to understand (and you can read it too)…
What you need to know is that, if you want to update by using the from_form() method, you can pass it three parameters:
1. the validation rules (if you don’t have them inside the $rules array)
2. additional data that can be inserted beside the form data
3. the form field(s) or in our case the additional data key that will be used to identify the row that will be updated.