duclet Posted February 21, 2008 Share Posted February 21, 2008 I am currently writing a script that will hopefully handle all of my form processing in the future. Just started this recently and have only gotten to really finish up a couple of meaningful functions. There isn't any error or problem with it. I just want a second opinion of what people think of the code so far and if there are better ways to do certain things. I have set up a test page at: http://dev.scripts.tiger-inc.com/php/Tests/DLForm.php Obviously, this script uses some functionality of other scripts that I have written so if you see a class or function you don't recognize, just ignore it and assume that the function works as it is intended to be. Since I usually make my function names descriptive, you should be able to guess what that function should do. The comments in the code should be able to explain the process or logic behind things but if you still have questions, feel free to ask. Again, I am only looking for a second opinion to see if there is a better way to handle certain situations. I know there are other scripts out there that handle form creation and stuff but this is only for me. Also, this is by no means complete either. Thanks for any helpful comments to be posted though. Here is the source code: <?php /* Load neccessary files */ loadClass('DLForm'); /** * Form Management. This class makes use of the following namespaces: * * @author Duc Tri Le * @copyright Copyright (c) 2008, Duc Tri Le * @version 1.0 - : Initial release. * 0.0 - February 7, 2008: Started. */ class DLForm { /* ********************************************************************** */ /* Data Member */ /* ********************************************************************** */ /** * The time, in seconds, of how long to keep cached data. */ const CacheTime = 2592000; // 30 days /** * Represents an Input Button field. */ const InputButton = 1; /** * Represents an Input Checkbox field. */ const InputCheckbox = 2; /** * Represents an Input Checkbox field that is part of a group. */ const InputCheckboxGroup = 13; /** * Represents an Input File field. */ const InputFile = 3; /** * Represents an Input Hidden field. */ const InputHidden = 4; /** * Represents an Input Password field. */ const InputPassword = 5; /** * Represents an Input Radio field. */ const InputRadio = 6; /** * Represents an Input Radio field that is part of a group. */ const InputRadioGroup = 14; /** * Represents an Input Reset field. */ const InputReset = 7; /** * Represents an Input Submit field. */ const InputSubmit = 8; /** * Represents an Input Text field. */ const InputText = 9; /** * Represents an Option field. */ const Option = 10; /** * Represents a Select field. */ const Select = 11; /** * Represents a Textarea field. */ const Textarea = 12; /** * Used for validation: using a user defined function. */ const ValidateCustom = 103; /** * Used for validation: an e-mail address. */ const ValidateEmail = 100; /** * Used for validation: non empty string. */ const ValidateRequired = 101; /** * An array containing all of the form fields. */ private $fields; /* ********************************************************************** */ /* Constructor */ /* ********************************************************************** */ /** * Create a new DLForm item. * * @return DLForm */ public function __construct() { $this->fields = array(); } /* ********************************************************************** */ /* Public Methods */ /* ********************************************************************** */ /** * Add in a form field. * * @param string $name The name for the field. * @param int $type The type of the form fields. Use the * provided constants for this parameter. * @param array $attributes (Optional) Any extra attributes for the * field. The key of the array will be the attribute and its value is * the attribute's value. Also note that the value will be surrounded * by double quotes so be sure to add slashes appropriately. For all * OPTION fields, the attribute of 'text' will be the text between * the opening and closing option tags if it is given, otherwise * 'value' will be used. For all TEXTAREA fields, the attribute * 'value' will be the text between the opening and closing textarea * tags and won't be surrounded by double quotes. It will also be * passed through the function htmlentities. All other type of fields, * if the attribute 'text' isn't given, then 'value' will be used as * part of the label. Note that a label will not be included for a * OPTION or SELECT field. * @param array $options (Optional) This is specifies * configurations for this method. It consist of the following options: * Key Default Description * custom '' (callback) This is only used when * 'validate' is set to VALIDATECUSTOM. * This can either be a function name or * if it is a method, it needs to be a * static method given as an array where * the first item of the array is the class * name and second item being the name of * the method. Note that the the function/ * method will receive two parameters: the * $name and the current value. The * function/method should also return a * boolean as its result. * use_post TRUE (boolean) When this is set to TRUE, if * there is a Post variable with the same * name as the given $name, then the value * of that Post variable will be used as * the value. * validate 0 (int) Specify whether or not the given * field should be validated. Use the * provided constants for this. */ public function addField($name, $type) { // Get the optional parameters $attributes = @func_get_arg(2); $options = @func_get_arg(3); // Make sure they are arrays if(!is_array($attributes)) { $attributes = array(); } if(!is_array($options)) { $options = array(); } // Merge default options with given options $options = array_merge( array('custom' => '', 'use_post' => TRUE, 'validate' => 0), $options ); // Validate input(s) $test1 = !DLCommon::isNonEmptyString($name); $test2 = !is_int($type); $test3 = !is_bool($options['use_post']); $test4 = !is_string($options['custom']) && !is_array($options['custom']); $test5 = !is_int($options['validate']); foreach($attributes as $attribute) { if(!is_string($attribute)) { $test6 = TRUE; } } if($test1 || $test2 || $test3 || $test4 || $test5 || $test6) { return DLCommon::exitScript( 'DLForm->addField', compact('name', 'type', 'attributes', 'options'), compact('test1', 'test2', 'test3', 'test4', 'test5', 'test6') ); } if($type === DLForm::Option) { // If it is an option field, we need to group them // Make sure that a select field exist, if not create it $t1 = !is_array($this->fields[$name]); $t2 = $t1 ? TRUE : $this->fields[$name]['type'] !== DLForm::Select; if($t2) { $this->addField($name, DLForm::Select, array(), $options); } // Get all of the option fields for the given select if(is_array($this->fields[$name]['children'])) { $children = $this->fields[$name]['children']; } else { $children = array(); } // Add the field $this->fields[$name]['children'][] = array( 'name' => $name, 'type' => $type, 'attributes' => $attributes, 'options' => $options ); } elseif($type === DLForm::InputCheckboxGroup) { // If it is a checkbox or a radio and we want to group them // Add the field $this->fields[$name]['name'] = $name; $this->fields[$name]['type'] = $type; $this->fields[$name]['options'] = $options; $this->fields[$name]['children'][] = array( 'name' => $name, 'type' => DLForm::InputCheckbox, 'attributes' => $attributes, 'options' => $options ); } elseif($type === DLForm::InputRadioGroup) { // If it is a checkbox or a radio and we want to group them // Add the field $this->fields[$name]['name'] = $name; $this->fields[$name]['type'] = $type; $this->fields[$name]['options'] = $options; $this->fields[$name]['children'][] = array( 'name' => $name, 'type' => DLForm::InputRadio, 'attributes' => $attributes, 'options' => $options ); } else { // Add the field $this->fields[$name] = array( 'name' => $name, 'type' => $type, 'attributes' => $attributes, 'options' => $options ); } } /** * Retrieve the HTML for the given $field. * * @param string $name The name of the form field. * @param array $options (Optional) This is specifies * configurations for this method. It consist of the following options: * Key Default Description * - label TRUE (boolean) Specifies whether or not a * label tag should be included with the * resulting HTML. * @return string */ public function getField($name) { // Get the optional parameters $options = @func_get_arg(1); // Make sure it is an arrays if(!is_array($options)) { $options = array(); } // Merge default options with given options $options = array_merge(array('label' => TRUE), $options); // Validate input $test1 = !in_array($name, array_keys($this->fields)); $test2 = !is_bool($options['label']); if($test1 || $test2) { return DLCommon::cleanExit( 'DLForm->getField', compact('name', 'options'), array('test1', 'test2') ); } // Get the field $field = $this->fields[$name]; // Templates $tpt = DLData::get( 'DLForm.Templates.'.$field['type'], array('replace' => FALSE) ); $tpt2 = DLData::get( 'DLForm.Templates.Label', array('replace' => FALSE) ); // Text Replacement Engine $DLT = new DLTemplate(); // Depending on the field type, process appropriately switch($field['type']) { case DLForm::InputCheckbox: case DLForm::InputRadio: if(DLCommon::isNonEmptyString($field['attribute']['checked'])) { $attribute = sprintf( 'checked="%s" ', $field['attribute']['checked'] ); } case DLForm::InputButton: case DLForm::InputFile: case DLForm::InputHidden: case DLForm::InputPassword: case DLForm::InputReset: case DLForm::InputSubmit: case DLForm::InputText: // Make sure attribute is a string if(!is_string($attribute)) { $attribute = ''; } // Set some data $value = $this->getValue($field); $attribute .= $this->getAttributes($field).$value['value']; $DLT->ar('id', uniqid('DLForm_')); $DLT->ar('name', $name); $DLT->ar('text', $this->getText($field)); $DLT->ar('attributes', $attribute); // Process $result = ''; if($options['label']) { $result = $DLT->process($tpt2); } $result .= $DLT->process($tpt); return $result; case DLForm::InputCheckboxGroup: // Template $tpt3 = DLData::get( 'DLForm.Templates.'.DLForm::InputCheckbox, array('replace' => FALSE) ); // See if we have any post data we want to use $parentValue = $this->getValue( $field, array('value_only' => TRUE) ); // First get the HTML for the children $children = ''; foreach($field['children'] as $child) { // Get some data $attributes = $this->getAttributes($child); $text = $this->getText($child); $value = $this->getValue( $child, array('value_only' => TRUE) ); // If we have post data & the data match if($parentValue['is_post'] && in_array($value['value'], $parentValue['value'])) { $checked = 'checked="checked" '; } elseif(!$parentValue['is_post']) { $checked = sprintf( 'checked="%s" ', $child['attributes']['checked'] ); } else { $checked = ''; } // Set some data $value = $this->getValue($child); $DLT->ar('id', uniqid('DLForm_')); $DLT->ar('name', $name.'[]'); $DLT->ar('text', $text); $DLT->ar( 'attributes', $attributes.$checked.$value['value'] ); // Process if($options['label']) { $children .= $DLT->process($tpt2); } $children .= $DLT->process($tpt3); $DLT->reset(); } // Set some data $DLT->ar('children', $children); // Process $result = $DLT->process($tpt); return $result; case DLForm::InputRadioGroup: // Template $tpt3 = DLData::get( 'DLForm.Templates.'.DLForm::InputRadio, array('replace' => FALSE) ); // See if we have any post data we want to use $parentValue = $this->getValue( $field, array('value_only' => TRUE) ); // First get the HTML for the children $children = ''; foreach($field['children'] as $child) { // Get some data $attributes = $this->getAttributes($child); $text = $this->getText($child); $value = $this->getValue( $child, array('value_only' => TRUE) ); // If we have post data if($parentValue['is_post'] && ($value['value'] == $parentValue['value'])) { $checked = 'checked="checked" '; } elseif(!$parentValue['is_post']) { $checked = sprintf( 'checked="%s" ', $child['attributes']['checked'] ); } else { $checked = ''; } // Set some data $value = $this->getValue($child); $DLT->ar('id', uniqid('DLForm_')); $DLT->ar('name', $name); $DLT->ar('text', $text); $DLT->ar( 'attributes', $attributes.$checked.$value['value'] ); // Process if($options['label']) { $children .= $DLT->process($tpt2); } $children .= $DLT->process($tpt3); $DLT->reset(); } // Set some data $DLT->ar('children', $children); // Process $result = $DLT->process($tpt); return $result; case DLForm::Select: // Template $tpt3 = DLData::get( 'DLForm.Templates.'.DLForm::Option, array('replace' => FALSE) ); // See if we have any post data we want to use $parentValue = $this->getValue( $field, array('value_only' => TRUE) ); // First get the HTML for the children $children = ''; foreach($field['children'] as $child) { // Get some data $attributes = $this->getAttributes($child); $text = $this->getText($child); $value = $this->getValue( $child, array('value_only' => TRUE) ); // If we have post data if($parentValue['is_post'] && is_string($parentValue['value']) && ($value['value'] == $parentValue['value'])) { // And there is only one selected value $selected = 'selected="selected" '; } elseif($parentValue['is_post'] && is_array($parentValue['value']) && in_array($value['value'], $parentValue['value'])) { // And there are multiple selections $selected = 'selected="selected" '; } elseif(!$parentValue['is_post']) { $selected = sprintf( 'selected="%s" ', $child['attributes']['selected'] ); } else { $selected = ''; } // Set some data $value = $this->getValue($child); $DLT->ar('id', uniqid('DLForm_')); $DLT->ar('text', $text); $DLT->ar( 'attributes', $attributes.$selected.$value['value'] ); // Process $children .= $DLT->process($tpt3); $DLT->reset(); } // Could this SELECT field have more than one value? if($field['attributes']['size'] > 1) { $name .= '[]'; } // Set some data $DLT->ar('id', uniqid('DLForm_')); $DLT->ar('name', $name); $DLT->ar('attributes', $this->getAttributes($field)); $DLT->ar('text', $this->getText($field)); $DLT->ar('children', $children); // Process $result = ''; if($options['label']) { $result = $DLT->process($tpt2); } $result .= $DLT->process($tpt); return $result; case DLForm::Textarea: // Set some data $value = $this->getValue($field); $DLT->ar('id', uniqid('DLForm_')); $DLT->ar('name', $name); $DLT->ar('attributes', $this->getAttributes($field)); $DLT->ar('text', $this->getText($field)); $DLT->ar('value', $value['value']); // Process $result = ''; if($options['label']) { $result = $DLT->process($tpt2); } $result .= $DLT->process($tpt); return $result; default: // Field doesn't exist return DLCommon::exitScript( 'DLForm->getValue', compact('field', 'options') ); } } /** * Nicely output the content of this class. Serves as a debugging service. * * @return string */ public function toString() { ob_start(); echo '<pre>'; foreach($this->fields as $field) { printf("<h2>%s:</h2><div>%s</div>\n", $field['name'], print_r($field, 1)); } echo '</pre>'; $result = ob_get_contents(); ob_end_clean(); return $result; } /* ********************************************************************** */ /* Private Methods */ /* ********************************************************************** */ /** * Retrieve a string representation of the attributes for the given $field. * Note that this will not return the 'text' or 'value' attribute. Use the * method 'getText' and 'getValue' for that. The attribute 'selected' is * also omitted from this and is retrieved via the method 'getValue' as * well. * * @param array $field An associative array that contains the * field information. * @return string */ private function getAttributes($field) { // Validate input if(!is_array($field)) { return DLCommon::exitScript( 'DLForm->getAttributes', compact('field'), array('test1' => TRUE) ); } // If the data is for the field InputCheckboxGroup or InputRadioGroup, // just return an empty string switch($field['type']) { case DLForm::InputCheckboxGroup: case DLForm::InputRadioGroup: return ''; } // Create the string $result = ''; foreach($field['attributes'] as $attribute => $value) { switch($attribute) { case 'checked': case 'selected': case 'text': case 'value': break; default: $result .= sprintf( '%s="%s" ', $attribute, addcslashes($value, '"') ); } } return $result; } /** * Retrieve the text for the given $field. By default, if the attribute * 'text' exist for the given $field, it is returned, otherwise, the value * of the attribute 'value' will be used instead. If 'value' is also empty, * then use the 'name' of the field, capitalizing the first letter. * * @param array $field The field in which the text should be * retrieved for. * @return string */ private function getText($field) { // Validate input if(!is_array($field)) { return DLCommon::exitScript( 'DLForm->getText', compact('field'), array('test1' => TRUE) ); } // Get the text from the attributes $result = $field['attributes']['text']; // Make sure we have a non-empty string, otherwise, get the value if(!DLCommon::isNonEmptyString($result)) { $result = $this->getValue($field, array('value_only' => TRUE)); $result = $result['value']; } // If we still have a empty string, get the name if(!DLCommon::isNonEmptyString($result)) { $result = ucfirst($field['name']); } return $result; } /** * Retrieve the value for the given $field. This method will return an * associative array with the following keys: * - is_post: specifies whether or not the value is from POST * - value: the actual value itself * * @param array $field The field in which the value should be * retrieved for. * @param array $options (Optional) This is specifies * configurations for this method. It consist of the following options: * Key Default Description * - value_only FALSE (boolean) If set to TRUE, then only * the value will be returned, * otherwise, the value will be wrapped * around by the value attribute. * @return array */ private function getValue($field) { // Get the optional parameters $options = @func_get_arg(1); // Make sure it is an arrays if(!is_array($options)) { $options = array(); } // Merge default options with given options $options = array_merge(array('value_only' => FALSE), $options); // Validate input $test1 = !is_array($field); $test2 = !is_bool($options['value_only']); if($test1 || $test2) { return DLCommon::exitScript( 'DLForm->getValue', compact('field', 'options'), compact('test1', 'test2') ); } // Depending on the field type, process appropriately $use_post = $field['options']['use_post']; switch($field['type']) { case DLForm::InputButton: case DLForm::InputCheckbox: case DLForm::InputFile: case DLForm::InputHidden: case DLForm::InputPassword: case DLForm::InputRadio: case DLForm::InputReset: case DLForm::InputSubmit: case DLForm::Option: // These can never use post data to have its value overwritten $result['is_post'] = FALSE; $result['value'] = $field['attributes']['value']; break; case DLForm::InputCheckboxGroup: case DLForm::InputRadioGroup: case DLForm::InputText: case DLForm::Select: // These could read data from post // See if we should be using the post value and it exist if($use_post && isset($_POST[$field['name']])) { $result['is_post'] = TRUE; $result['value'] = $_POST[$field['name']]; } else { $result['is_post'] = FALSE; $result['value'] = $field['attributes']['value']; } break; case DLForm::Textarea: // These can read from post but should be html entified if($use_post && isset($_POST[$field['name']])) { $result['is_post'] = TRUE; $result['value'] = $_POST[$field['name']]; } else { $result['is_post'] = FALSE; $result['value'] = $field['attributes']['value']; } $result['value'] = htmlentities($result['value']); break; default: // Field doesn't exist return DLCommon::exitScript( 'DLForm->getValue', compact('field', 'options') ); } // Return the value only if it is requested and it isn't a TEXTAREA if(!$options['value_only'] && ($field['type'] !== DLForm::Textarea)) { $result['value'] = sprintf( 'value="%s" ', addcslashes($result['value'], '"') ); } return $result; } } ?> Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.