Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Codeigniter - re-populating form on failed validation after submitting

I have a form that requires the user to enter some information. If they fail to complete the required fields they are re-presented with the form; the top of the page notifying them what fields are required and I've enabled sticky forms (set_value()) so their input is not lost.

I'm using flashdata to display messages to the user (i.e., if what they've entered already exists in the database).

My form is in the index method of my controller. When submit is clicked from my view it calls the add() method in my controller. The add() method performs the validation and depending on the results either submits to the database or kicks back out to the user to get more data.

I have several issues with the way that i've done this. 1. If validation fails I'm using $this->index() to get back to my form and display the validation errors. If I try using redirect, I lose my validation errors and my $_POST[] data so my sticky forms end up blank. 2. Using $this->index() appends the 'add' to the end of my url 3. Using $this->index() causes issues with the flashdata. Random results.

Any ideas?

<?php
class Restaurant extends Controller {

    function Restaurant() {
        parent::Controller();
    }

    function index() {

        // Load libraries and models
        $this->load->model('/restaurant/mRestaurantTypes');
        $this->load->model('/restaurant/mRestaurant');
        $this->load->model('/utilities/mUtilities');

        // Get states
        $stateSelect = array();
        $getStates = $this->mUtilities->getStates();

        if($getStates->num_rows() > 0) {
            foreach($getStates->result() as $row) {
                $stateSelect[$row->abbr] = $row->name;
            }
        }


        // Get restaurant types
        $restaurantTypes = array();
        $getRestaurantTypes = $this->mRestaurantTypes->getRestaurantTypes();

        if($getRestaurantTypes->num_rows() > 0) {
            foreach($getRestaurantTypes->result() as $row) {
                $restaurantTypes[$row->restaurant_types_id] = $row->type;
            }
        }

        // Create form elements
        $data['name'] = array(
            'name'      =>  'name',
            'id'        =>  'name',
            'value'     =>  set_value('name'),
            'maxlength' =>  '200',
            'size'      =>  '50'
        );

        $data['address'] = array(
            'name'      =>  'address',
            'id'        =>  'address',
            'value'     =>  set_value('address'),
            'maxlength' =>  '200',
            'size'      =>  '50'
        );

        $data['city'] = array(
            'name'      =>  'city',
            'id'        =>  'city',
            'value'     =>  set_value('city'),
            'maxlength' =>  '50',
            'size'      =>  '25'        
        );

        $data['state'] = $stateSelect;

        $data['zip'] = array(
            'name'      =>  'zip',
            'id'        =>  'zip',
            'value'     =>  set_value('zip'),
            'maxlength' =>  '10',
            'size'      =>  '10'    
        );

        $data['phone'] = array(
            'name'      =>  'phone',
            'id'        =>  'phone',
            'value'     =>  set_value('phone'),
            'maxlength' =>  '15',
            'size'      =>  '15'    
        );

        $data['url'] = array(
            'name'      =>  'url',
            'id'        =>  'url',
            'value'     =>  set_value('url'),
            'maxlength' =>  '255',
            'size'      =>  '50'    
        );

        $data['type'] = $restaurantTypes;

        $data['tags'] = array(
            'name'      =>  'tags',
            'id'        =>  'tags',
            'value'     =>  set_value('tags'),
            'maxlength' =>  '255',
            'size'      =>  '50'    
        );

        $data['active'] = array(
            'name'      =>  'active',
            'id'        =>  'active',
            'value'     =>  'Y',
            'maxlength' =>  '1',
            'size'      =>  '2' 
        );

        // Set page variables
        $data_h['title'] = "Add new restaurant";

        // Load views
        $this->load->view('/template/header', $data_h);
        $this->load->view('/restaurant/index', $data);
        $this->load->view('/template/footer');      

    }


    /**
     * Add the the new restaurant to the database.
     */
    function add() {

        // Load libraries and models
        $this->load->library('form_validation');
        $this->load->model('/restaurant/mRestaurant');

        // Define validation rules
        $this->form_validation->set_rules('name',       'Name',     'trim|required|max_length[255]|xss_clean');
        $this->form_validation->set_rules('address',    'Address',  'trim|required|max_length[100]|xss_clean');
        $this->form_validation->set_rules('city',       'City',     'trim|required|max_length[128]|xss_clean');
        //$this->form_validation->set_rules('state',        'State',    'trim|required');
        $this->form_validation->set_rules('zip',        'Zip',      'trim|required|max_length[128]|xss_clean');
        $this->form_validation->set_rules('phone',      'Phone',    'trim|required|max_length[10]|xss_clean');
        $this->form_validation->set_rules('url',        'URL',      'trim|required|max_length[255]|xss_clean');
        $this->form_validation->set_rules('tags',       'Tags',     'trim|xss_clean');


        // Form validation
        if ($this->form_validation->run() == FALSE) {

            // On failure
            $this->index();

        } else {

            // On success, prepare the data
            $data = array(
                'name'      =>  $_POST['name'],
                'address'   =>  $_POST['address'],
                'city'      =>  $_POST['city'],
                'state'     =>  $_POST['state'],
                'zip'       =>  $_POST['zip'],
                'phone'     =>  $_POST['phone'],
                'url'       =>  $_POST['url'],
                'type'      =>  $_POST['type'],
                'tags'      =>  $_POST['tags'],
                'active'    =>  $_POST['active'],
            );

            // Check if the restaurant already exists
            $check = $this->mRestaurant->getRestaurant($data['name'], $data['zip']);

            // If no records were returned add the new restaurant
            if($check->num_rows() == 0) {
                $query = $this->mRestaurant->addRestaurant($data);

                if ($query) {
                    // On success
                    $this->session->set_flashdata('status', '<div class="success">Added New Restaurant!</div>');
                } else {
                    // On failure
                    $this->session->set_flashdata('status', '<div class="error">Could not add a new restaurant.</div>');    
                }

                redirect('restaurant/confirm', 'refresh');
            } else {
                // Notify the user that the restaurant already exists in the database
                $this->session->set_flashdata('status', '<div class="notice">This restaurant already exists in the database.</div>');
                redirect('restaurant/index');
            }

        }

    }


    function confirm() {

        $data['title'] = "Confirm";

        $this->load->view('/template/header');
        $this->load->view('/restaurant/confirm', $data);
        $this->load->view('/template/footer');
    }
}
?>
like image 534
mazer Avatar asked Dec 29 '09 09:12

mazer


3 Answers

I will try to help with the logic in the controller that I always use:

function index()
{
  //set some default variables
  $data['error_message'] = '';
  //if this is to edit existing value, load it here
  // from database and assign to $data
  //...
  //set form validation rules
  $validation = array();
  $validation['field_name'] = array(
    'field' => 'field_name',
    'label' => 'Field label',
    'rules' => 'trim|required'
  );
  //more rules here
  //...
  $this->load->library('form_validation');
  $this->form_validation->set_rules($validation);
  //run validation
  if ($this->form_validation->run() == FALSE)
  {
    $data['error_message'] .= validation_errors();
  }
  else
  {
    //do insert/update
    //
    //it's better to do redirection after receiving post request
    //you can use flashdata for success message
    if ( $success )
    {
      $this->session_set_flashdata('success_message', MESSAGE_HERE);
    }
    redirect(RESULT_PAGE);
  }
  //reaching this block can have 2 meaning, direct page access, or not have valid form validation
  //assign required variables, such as form dropdown option, etc
  //...
  //load view
  $this->load->view(VIEW_FILE, $data);
}

View file:

...
<?php if ( $error_message ): ?>
  <?php echo $error_message; ?>
<?php endif; ?>
<?php echo form_open(current_url, array('id' => 'some_form_id')); ?>
<!-- form field here -->
<label for="field_name">Field label</label>
<input name="field_name" value="<?php echo set_value('field_name', $DEFAULT_FIELD_NAME_IF_NEEDED); ?>" />
<!-- more form field here -->
<?php echo form_close(); ?>
...

I hope this will help you.

For the $DEFAULT_FIELD_NAME_IF_NEEDED in the view file, I use this to pass the default value if this form page is to edit existing data from database. You can load the data in the controller, then pass it to view file and display it in the form field.

like image 199
Donny Kurnia Avatar answered Oct 03 '22 00:10

Donny Kurnia


-------controller-------

$data['post'] = $_POST;
$this->load->view('view/view', $data);

then in your view

<input type="text" value="><?=$post['username'];?>" name="username">

like image 24
Tom Schlick Avatar answered Oct 03 '22 02:10

Tom Schlick


I had a similar problem and I ended up doing:

My form is to create new user but you should get the idea.

    if($this->form_validation->run() == FALSE) 
        {
            $this->data['title'] = "Add User";
            $this->load->vars($this->data);
            $this->load->view('head');
            $this->load->view('header');
            $this->load->view('admin/sidebar');
            $this->load->view('admin/add_user');
            $this->load->view('footer');
        }

So effectively instead of calling new function I was showing new view from the same function. Not the nicest solution but it works. Also you might want to use something like this to check if the restaurant already exists:

function _check_username($str) 
{
    $this->db->where('username', $str);
    $query = $this->db->get('sm_users');

    if($query->num_rows() == 0)
    {
        return TRUE;
    }
    else
    {
        $this->form_validation->set_message('_check_username', "User '$str' already exists!");
        return FALSE;
    }
}

And use callback validation function:

$this->form_validation->set_rules('userName','User Name','trim|required|min_length[3]|callback__check_username');
like image 35
LukeP Avatar answered Oct 03 '22 02:10

LukeP