-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Form Library
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).
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
- Built in validation using CI Validation
- 1 call data retrieval
- XHTML 1.0 output code
- written for PHP5 (not PHP4 compatible)
$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();
}
<?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>