Part of the EllisLab Network
x
 
Create New Page
 View Previous Changes    ( Last updated by George Petsagourakis )

Form Library

Category:Library | Category:Library -> Community | Category:Library -> Forms

The Form library is a complete replacement for the Form helper. It reads an XML document and converts it to an array (via the Xml Library).

Updates

2006-12-08:
* New version, some API changes (options in dropdowns are reversed from previous order!)
* Entire library has been cleaned up and optimized a bit
* Now integrates with the Uploader library to allow the creation of upload forms

2006-11-06:
* <required> is no longer needed, validation rules are used to find required fields
* Changed several bits, parse by fieldsets
* Changed the format of form templates

2006-11-04:
* Made validate() set the form values, no need to set them manually
* Tweaked the valid types and attributes

Features

- Built in validation using CI Validation
- 1 call data retrieval
- XHTML 1.0 output code
- written for PHP5 (not PHP4 compatible)

Usage

$this->load->library('form');
$this->form->load('login'); // Relative to APPPATH/data/forms/, ".xml" appended
if ($data = $this->form->post_data()) {
  print_r
($data);
}
else {
  
print $this->form->build();
}

Library Code

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

/***
* Form library for CodeIgniter
*
*    author: Woody Gilk
* copyright: (c) 2006
*   license: http://creativecommons.org/licenses/by-sa/2.5/
*      file: libraries/Form.php
*/

class Form {

    public
function Form () {
    
/***
     * @constructor
     */
        
$obj =& get_instance();    
        
$obj->load->library('xml');
        
$this->ci =& $obj;  
    
} /*** END ***/
    
    
private $ci;

    
/*** Public variables ***/
    
public $error     = '';
    
public $set_error = '';
    
public $output    = '';

    
/*** Internal variables ***/
    
private $action;
    
private $rules;
    
private $upload_rules;
    
private $data;
    
private $set_data;
    
private $elements        = array();
    
private $elements_upload = array();
    
private $uploaded_files  = array();
    
private $has_upload = false;

    
public function load ($name) {
    
/***
     * @public
     * Load a form definition for parsing
     */
        
if (! $this->ci->xml->load ("data/forms/$name")) {
            $this
->error = "Failed to load form: $name";
            return
false;
        
}

        
// Reset sensative vars to default value
        
$this->action = '';
        
$this->rules  = '';
        
$this->data   = '';
        
$this->set_data   = '';
        
$this->set_error  = '';
        
$this->has_upload = false;
        
$this->elements   = array();

        
$data = $this->ci->xml->parse ();
        if (!
is_array($data)) {
            $this
->error = "No form data found in /data/forms/$name.xml";
            return
false;  
        
}
        
else {
            $data
= $data['form'][0];

            
$this->data     = $data;
            
$this->action   = $data['__attrs']['action'];

            
$this->get_fields ($data);

            
$this->elements        = array_unique($this->elements);
            
$this->elements_upload = array_unique($this->elements_upload);
        
}   

        
return true;
    
} /*** END load ***/  

    
private function get_fields ($array) {
    
/***
     * @private
     * Extract the rules and field names from the data
     */  
        
if (! is_array($array)) {
            
return;
        
}

        
foreach ($array as $key => $val) {
               
if ($key == 'fieldset' && is_array ($val)) {
                    
foreach ($val as $_val) {
                    $this
->get_fields ($_val);
                
}
            }
            
elseif (! is_numeric ($key) && $key != '__attrs' && $key != 'fieldset') {
                
foreach ($val as $_key => $_val) {
                    
if (isset ($_val['__attrs']) && $_attrs = $_val['__attrs']) {
                        
if (isset ($_attrs['rules'])) {
                            $this
->rules[$key] = $_attrs['rules'];
                           
}
                          
if (isset ($_attrs['allow'])) {
                            $this
->upload_rules[$key] = $_attrs['allow'];
                        
}
                          }

                    
if (isset ($_val['type']) && $_val['type'][0] == 'file') {
                        $this
->has_upload        = true;
                        
$this->elements_upload[] = $key;
                    
}
                    
else {
                                $this
->elements[] = $key;
                     
}                            
                }
// end foreach
            
} //end elseif   
        
}
    }
/*** END get_fields ***/   

    
public function set_action ($location) {
    
/***
     * @public
     * Set the form action
     */  

        
$this->action = $location;
        return
true;
    
} /** END action ***/  

    
public function set ($element, $key, $value = false) {
    
/***
     * @public
     * Set an attribute of an element, or a new elemenet
     */  
        
if (is_array ($key)) {
            
foreach($key as $_key => $_value) {
                $this
->set($element, $_key, $_value);
            
}

            
return true;
        
}  

        $this
->set_data[$element][$key] = $value;
        return
true;
    
} /*** END set ***/

    
public function post_data ($validate = true) {
    
/***
    * @public
    * Return all the post data from the loaded form
    */
        
if ($validate == true && ! $this->validate ()) {
            
return false;
        
}
        
if (@ count($this->elements) < 1) {
            
return false;
        
}  

        $data  
= array ();
        foreach (
$this->elements as $elem) {
            $data[$elem]
= stripslashes ($this->ci->input->post ($elem));
        
}

        
return array_merge($data, $this->uploaded_files);
    
} /*** END post_data ***/

    
private function do_uploads() {
        
/***
         * @private
         * Helper function for validation
         */
        
$error = false;
        
$data  = array();
        if (
count ($this->elements_upload) > 0) {
            $config[
'upload_path']   = isset ($this->upload_path) ? $this->upload_path : './upload/';
            
$config['remove_spaces'] = true;
            
$config['xss_clean']     = true;
            
$config['max_size']      = '2048';

            
$this->ci->load->library ('upload');

            foreach (
$this->elements_upload as $elem) {
                
// Reset the configuration
                
if (is_array ($this->upload_rules) && isset($this->upload_rules[$elem])) {
                    $config[
'allowed_types'] = $this->upload_rules[$elem];
                
}

                
if (isset ($this->rules[$elem]) && $rules = $this->rules[$elem]) {
                    $required
= strpos ($rules, 'required') !== false ? true : false;
                
}
                
else {
                    $required
= false;
                
}
                    

                $this
->ci->upload->initialize ($config);

                if (
$this->ci->upload->do_upload ($elem)) {
                    $return
= $this->ci->upload->data();
                    
$this->uploaded_files[$elem] = $return;
                
}
                
elseif ($required == true) {
                    $error
= true;
                
                    
$errors = $this->ci->upload->display_errors();
                    
$this->set_error .= $errors;
                
}
            }
        }

        
return ($error == true ? false : true);
    
} /* END do_uploads */

    
public function validate ($name = false) {
    
/***
     * @public
     * Validates a form based on the rules found in the definition
     */    
        
if ($name != false && ! $this->load ($name)) {
            
return false;
        
}
        
elseif (! is_array ($this->rules)) {
            
if (count ($this->elements_upload) > 0) {
                
return $this->do_uploads();
            
}

            
return false;
        
}

        $this
->ci->load->library ('validation');
        
$this->ci->validation->set_rules ($this->rules);

        if (
$this->ci->validation->run() && $this->do_uploads())  {
             
return true;
        
}
        
else {
            
foreach ($this->post_data (false) as $key => $val) {
                
// Set default values
                
$this->set($key, 'value', $val);
            
}   
            
            
foreach ($this->ci->validation->_error_array as $error) {
                $this
->set_error .= "\t<p>$error</p>\n";
            
}  
        }

        
return false;
    
} /*** END validate ***/  

    
private function build_group ($group, $depth = 0) {  
    
/***
     * @private
     * Build a fieldset
     */
        
static $first_run;
        static
$tabindex;
        
        
$tabindex = isset ($tabindex) ? $tabindex : 1;

        
// Set the valid attributes and type values
        
$valid_attr = array(
            
'type', 'maxlength', 'value', 'options',
            
'selected', 'checked', 'rows', 'cols', 'size',
            
'onclick', 'onmouseover', 'onmouseout', 'onchange'
        
);
        
$valid_type = array(
            
'text', 'textarea', 'password', 'file',
            
'dropdown', 'radio', 'checkbox',
            
'submit', 'button', 'hidden'
        
);
        
$tabs = repeater("\t", $depth);

        
$html  = sprintf ("$tabs".'<fieldset><legend>%s</legend>'."\n", $group['__attrs']['name']);
        if (
$first_run !== false) {
            $errors
= '<div class="error message">'."\n\t". $this->set_error ."\n\t</div>";
            
$html .= "$tabs". preg_replace("|\n\t+|", "\n$tabs\t", $errors) ."\n";
            
$first_run = false;
        
}
        
if (isset ($group['__attrs']['text']) && $text = $group['__attrs']['text']) {
            $html
.= "$tabs\t<p>$text</p>\n";
        
}

        $html
.= "$tabs\t".'<ol class="layout">'."\n";

        foreach (
$group as $name => $val) {
            
if ($name == '__attrs') {
                
continue;
            
}
            
elseif ($name == 'fieldset') {
                
foreach ($val as $_group) {
                    $html
.= "$tabs\t<li>\n". $this->build_group ($_group, $depth+2) ."$tabs\t</li>\n";
                
}
            }
            
else {
                
foreach ($val as $index => $def) {
                    
foreach ($def as $key => $val) {
                        
if ($key == '__attrs') {
                            
unset ($def[$key]);
                            continue;
                        
}

                        $def[$key]
= $val[0];
                    
}

                    
// Skips defs that have no type attribute
                    
if (! isset($def['type']) || ! in_array ($def['type'], $valid_type)) {
                        
continue;
                    
}

                    
// Externally set data is present, merge with stored efinition
                    
if (isset ($this->set_data[$name]) && is_array ($this->set_data[$name])) {
                        
if ($def['type'] == 'checkbox' && isset ($this->set_data[$name]['value'])) {
                            $this
->set_data[$name]['checked'] = (bool)$this->set_data[$name]['value'];
                            unset (
$this->set_data[$name]['value']);    
                        
}
                        
elseif ($def['type'] == 'submit' && isset ($this->set_data[$name]['value'])) {
                            
unset ($this->set_data[$name]['value']);    
                        
}

                        $def
= array_merge($def, $this->set_data[$name]);
                    
}

                    
// We always want a default value
                    
$def['value'] = isset($def['value'])
                        ?
$def['value'] : '';

                    
// Choose a label
                    
$label = isset($def['label'])
                         ?
ucwords($def['label'])
                        :
ucwords($name);

                    
// Create the id and name attributes
                    
$idname = $def['type'] != 'hidden'
                        
? sprintf('tabindex="%s" name="%s"', $tabindex++, $name)
                        :
sprintf('name="%s"', $name);

                    
// Add "*" on required items
                    
$label = isset($this->rules[$name]) && in_array('required', explode('|', $this->rules[$name]))
                        ?
"$label <em>*</em>"
                        
: $label;

                    
$row  = "";
                    
$row .= $def['type'] != 'hidden'
                        
? "$tabs\t<li>\n"
                        
: '';

                    
$row .= $def['type'] != 'submit' && $def['type'] != 'hidden'
                        
? "$tabs\t\t<label>$label</label>\n" : '';

                    
// Handle non-input elements
                    
switch ($def['type']) {
                    
case 'textarea':
                        
$input  = "$tabs\t\t<textarea $idname %s>". $def['value'] ."</textarea>\n";
                        unset (
$def['type'], $def['value']);
                        break;  
                    case
'dropdown':
                        
$def['value'] != false && $def['selected'] = $def['value'];
                        unset (
$def['value']);

                        if (isset (
$def['options'])) {
                            $options
= '';
                            foreach (
$def['options'] as $_key => $_val) {
                                $_val
= is_array ($_val) ? $_val[0] : $_val;

                                
$sel = isset ($def['selected']) && $def['selected'] == $_key
                                    
? ' selected="selected"' : '';

                                
$options .= "$tabs\t\t\t<option value=\"$_key\"$sel>$_val$tabs</option>\n";
                            
}
                            
unset ($def['type'], $def['options'], $def['selected']);

                            
$input = "$tabs\t\t<select $idname %s >\n$options$tabs\t\t</select>\n";
                        
}
                        
else {
                            
continue(2);
                        
}
                        
break;
                    case
'hidden':
                        
$input = "$tabs\t<input $idname %s style=\"display:none;\" />\n";
                        break;
                    default:
                        
$input = "$tabs\t\t<input $idname %s />\n";
                    
}     

                    
// Parse attributes
                    
$attributes = '';
                    foreach (
$def as $attr => $val) {
                        
if (in_array ($attr, $valid_attr)) {
                            
if ($attr == 'checked' && $val != false) {
                                $val
= 'checked';
                            
}
                            
elseif ($attr == 'checked') {
                                
continue;
                            
}

                            $attributes
.= " $attr=\"$val\" ";
                        
}
                    }
            
                    $row
.= sprintf($input, $attributes);
                     
$row .= isset($def['type']) && $def['type'] == 'hidden'
                        
? ''
                        
: "$tabs\t</li>\n";

                    
$html .= "$row";
                
}
            }             
        }  

        $html
.= "$tabs\t".'</ol>'."\n";
        
$html .= "$tabs".'</fieldset>'."\n";

        return
$html;
    
} /* END build_group */

    
public function build ($name = false) {
    
/***
     * @public
     * Convert a form definition into an XHTML form
     */
        
if ($name != false && ! $this->load ($name)) {
            
return false;
        
}
        
elseif (! is_array ($this->data)) {
            
return false;
        
}  
    
        $this
->ci->load->helper('string');

        
$form_type = $this->has_upload == true
            
? ' enctype="multipart/form-data"'
            
: '';

        
$out =& $this->output;
        
$out  = '';
        
$out .= sprintf("".'<form action="%s" id="%s" method="post"%s>'."\n",
            
site_url($this->action),
            
strtolower(preg_replace('|\W|', '_', $this->data['__attrs']['name'])),
            
$form_type
        
);

        foreach (
$this->data['fieldset'] as $group) {
            $out
.= $this->build_group($group);
        
}

        $out
.= "</form>\n";

        
$this->output = $out;
        return
$out;   
    
} /*** END build ***/

}

?>

Sample Form:

<?xml version="1.0" encoding="UTF-8" ?>
<form action="user/login" name="user_login">
  <
fieldset name="User Login">
    <
username rules="trim|required|min_length[4]|max_length[32]|xss_clean">
      <
type>text</type>
      <
maxlength>32</maxlength>
    </
username>
    <
password rules="required|min_length[4]|max_length[32]|xss_clean">
      <
type>password</type>
      <
maxlength>32</maxlength>
    </
password>
    <
fieldset name="Submit">
      <
submit>
        <
type>submit</type>
        <
value>Login</value>
      </
submit>
    </
fieldset>
  </
fieldset>
</
form>

Categories: