Blog Archive

Wednesday 1 May 2013

Putting the Form Builder class to work in FUEL CMS

Building forms in HTML is rarely a pleasure, so any functionality that aids that chore is a boon. Codeigniter has some form helper functions that are handy, and separately, the Validation class to prepare form data for processing. FUEL CMS builds on these to create the seriously useful Form Builder class.

In this tutorial I will show how useful it can be by building a form with CAPTCHA capabilities, and error responses.  I will be using v1.0 of FUEL CMS. I will use the CAPTCHA library found here CodeIgniter-Captcha

The form

 The source fields for the Form Builder class can be stored as an array, so why not create a config file for forms? In the application/config folder, create a file imaginatively called "forms.php". This can store one or more forms, and in this example it will have a "contact us" type form like so:


/* 
* CONTACT FORM
 */
$config['contact']['form'] = array(
  'required_text' => '* required fields',
  'css_class' => 'regular',
  'form_attrs' => array('method' => 'post'),
  'submit_value' => 'Send'
);

/* Setup fields */
$config['contact']['fields'] = array(
  'name' => array('type' => 'text', 'label' => 'Your name', 'required' => TRUE),
  'email' => array('type' => 'text', 'label' => 'Your email', 'required' => TRUE),
  'telephone' => array('label' => 'Your telephone'),
  'enquiry' => array('type' => 'textarea', 'label' => 'Your enquiry', 'required' => TRUE) 
);


The configuration for Form Builder is in 2 parts - the form itself, and then the fields. The keys for the fields are self explanatory, the form configuration keys are more complex - some are attributes, others are HTML snippets.

How do we put these to work in Form Builder? We will need to load the config file in our controller, and supply the "form" array as the configuration parameters to the class. So in a controller we can do:

class Contact extends CI_Controller {
    
  public $form_data;

  public function __construct() 
  {
    parent::__construct();
    // load contact config
   $this->load->config('forms');
   $this->form_data = $this->config->item('contact');
  }
...


For convenience I am putting the loaded "contact" array into a public variable. Later in the controller, Form Builder can be configured like so:

$this->load->library('form_builder', $this->form_data['form']);
$this->load->library('captcha');
$this->load->library('form_validation');


This configuration can occur in a method of your choosing - since this will be for an index page, my code was in the index() method. Note also I am loading the CAPTCHA library referred to above, and the form validation library.

As per the typical Codeigniter form validation, this same controller method should use some validation rules:

/* validators */
$this->form_validation->set_rules('name', 'Name', 'trim|required|max_length[128]|xss_clean');   
$this->form_validation->set_rules('email', 'Email', 'trim|required|max_length[256]|valid_email|xss_clean');
$this->form_validation->set_rules('telephone', 'Telephone', 'trim|max_length[24]|xss_clean');   
$this->form_validation->set_rules('enquiry', 'Enquiry', 'trim|min_length[8]|max_length[1024]|xss_clean');

// captcha rule - use codeigniter validation callback feature! NB we set function beginning with
// underscore so it won't get actioned by URL request - hence double underscore in callback 
// (callback convention + controller method convention)!
$this->form_validation->set_rules('captcha', 'CAPTCHA', 'required|callback__captcha_check');
$this->form_validation->set_message('_captcha_check', 'Text did not match the characters in the image');


The validations for the fields loaded by the forms.php config file are unremarkable, but something special is happening regarding the CAPTCHA input field - another method is being called (_captcha_check) within the rules argument. The method call is prefixed with "callback_" which is Codeigniter's way of implementing a function call for callbacks. So there will need to be another method in the controller like:

// CAPTCHA callback function - used by validation 
function _captcha_check($str)
{
  if($this->captcha->check($str))
     return TRUE;     
  else 
    return FALSE;   
}


The method follows the Codeigniter convention of beginning with an underscore so that it is not available as a URI request. The callback gets the string from the supplied input and uses the Captcha library to test if it matches the session string. A boolean return completes the validation.

So far, nothing has happened about the tiresome form construction! Here's how it will happen: we only need show the form either on initial load, or if the form has been submitted and failed validation, so inside of the validation test for "no validation"

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

  // create CAPTCHA img and field
  if($this->captcha->create()){
    $captcha = $this->captcha->html_data;
  } else {
    $captcha = 'Captcha : ' . $this->captcha->debug;
  }
  // append captcha html to text field of same name
  $captcha_html = "<p title='Input the characters in this image in the field below'>";
  $captcha_html .= img($captcha) ."</p>";
  $this->form_data['fields']['captcha']['before_html'] = $captcha_html;
    
  // See if submit has occurred (and failed) & populate fields
  // with submitted data, and append error too.
  if($this->input->post('Send'))
  {
    foreach($this->form_data['fields'] as $key => $val)
    {
      $this->form_data['fields'][$key]['value'] = $this->input->post($key);
      $this->form_data['fields'][$key]['after_html'] = form_error($key);
    }
  }
  $data['form'] = $this->form_builder->render_divs($this->form_data['fields']);
}



This is where Form Builder really comes into its own. Remember that earlier we created a class property array $this->form_data? The last line in the code snippet above builds the entire form from the config file array "fields" using this property. Using the class method render_divs(), it constructs the form using div tags to separate the label / input rows! That's it! Providing your CSS is up to snuff, the form should look fine already.

But what else is going on here? Two things: a CAPTCHA image is created using the library we referenced earlier, and inserted into an HTML sandwich, which is pre-pended to the CAPTCHA field. What CAPTCHA field?? We've been sneaky here and made a form field ("captcha") on the fly - and then been doubly sneaky by bolting it on with Form Builder's 'before_html' key so that the image appears above the text input field that will be validated by the rules we set earlier.

But wait, there's more! We then loop over the fields from the config array 'fields' index, and append any form errors using the key 'after_html', whilst also adding the submitted value back into the correct input's 'value' attribute. Double whammy!

And that is all contained in $data['form'], which is going to be part of the array we send to the view in Codeigniter fashion like so:

// use Fuel_page to render so it will grab all opt-in variables and do any necessary parsing  
$this->fuel->pages->render($view, $data);   


This view rendering is part of FUEL CMS' Pages class, but it's the same principle as if we used the Codeigniter load->view('view', $data) arrangement.

Thus all we need do in the view itself is echo out the form with:

<?php echo $form; ?>


So we should have:
  1. A nicely constructed form
  2. A captcha image and input field within it
  3. A form that validates itself, and reports errors and displays the submitted values


Wash, rinse, repeat.

No comments:

Post a Comment

My top artists