Skip to content
Derek Jones edited this page Jul 5, 2012 · 28 revisions

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:

  • 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

$error

\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".'
%s'."\n", $group['__attrs']['name']); if ($first_run !== false) { $errors = '
'."\n\t". $this->set_error ."\n\t
"
; $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

$text

\n"
; } $html .= "$tabs\t".'
    '."\n"; foreach ($group as $name => $val) { if ($name == '__attrs') { continue; } elseif ($name == 'fieldset') { foreach ($val as $_group) { $html .= "$tabs\t
  1. \n". $this->build_group ($_group, $depth+2) ."$tabs\t
  2. \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 *" : $label; $row = ""; $row .= $def['type'] != 'hidden' ? "$tabs\t
  3. \n" : ''; $row .= $def['type'] != 'submit' && $def['type'] != 'hidden' ? "$tabs\t\t$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\n"; } unset ($def['type'], $def['options'], $def['selected']); $input = "$tabs\t\t\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
  4. \n"
    ; $html .= "$row"; } } } $html .= "$tabs\t".'
'
."\n"; $html .= "$tabs".'
'
."\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">
  
4]|max_length[32]|xss_clean"> text 32 4]|max_length[32]|xss_clean"> password 32
submit Login
</form>

Clone this wiki locally