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

&lt;?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&lt;textarea $idname %s&gt;". $def['value'] ."&lt;/textarea&gt;\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&lt;input $idname %s style=\"display:none;\" /&gt;\n"; break; default: $input = "$tabs\t\t&lt;input $idname %s /&gt;\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("".'&lt;form action="%s" id="%s" method="post"%s&gt;'."\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 .= "&lt;/form&gt;\n"; $this->output = $out; return $out; } /*** END build ***/ } ?&gt;

Sample Form:

&lt;?xml version="1.0" encoding="UTF-8" ?&gt; &lt;form action="user/login" name="user_login"&gt; <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> &lt;/form&gt;
Clone this wiki locally