// -------------------------------------------------------- // This work is available under the terms of the Modified // BSD license: // // Copyright (c) 2005, Rutgers, The State University of New Jersey // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // 3. The name of the author may not be used to endorse or promote // products derived from this software without specific prior // written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING // IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // -------------------------------------------------------- // Authors: // This code was initially written by Alan Kugel. It // originally called the functions in forms.php as opposed // to generating code. It was then cleaned up and changed // into a code generator by John Fulton. // -------------------------------------------------------- // You can 'eval' the generated code with the eval function: // http://www.php.net/eval // or you can just print it and use it to build off of. // Everything that it generates should evaluate provided // that you've included forms.php. // -------------------------------------------------------- // Function: AutoForm // Description: Creates PHP code that calls functions // in forms.php to generate HTML forms // based on a DESCRIBE of an SQL table. // Type: public // Parameters: 2 required and 6 optional // [in] array $input An associative array of input options // Normally a copy of $_GET or $_POST // Used to set default values of the form // Set $input['next_action'] to submit's // name or there will be no submit button // [in] string $table The table that form is based on // A DESC will be done of this table // of the current database // (in) boolean $radio By default HTML SelectFields // AKA "pull-downs" are used for enums. // If this is field is true the // form will have radio buttons // instead // (Default: False) // (in) string $action Where form will submit to // e.g. "
" // (Default: $_SERVER['SCRIPT_NAME']) // (in) array $explicit_labels // Assoc array of explicit form labels. // AutoForm generates labels for inputs // based on field names such that: // "first_name" --> "First Name" // If you don't like the defualt: // ucwords(str_replace("_", " ", $field_name)) // which is how labels are set, then set // what fields are explicit like this: // $explicit_label = array('notes' => 'Special Notes'); // The above example makes the notes field // the label have "Special Notes" before the // input box // (Default: array() ) // (in) array $hidden_fields // Assoc array of fields in $table that you // don't want in the HTML form. e.g. if you // didn't want the field last_name to appear // in your form set this argument like this: // $hidden_fields = array('last_name'); // (Default: array() ) // (in) array $hidden_vars // Assoc array of variables (not in $table) // that you to be hidden (to pass along) // e.g. "" // "" // If you want something like the above do: // $hidden_vars = array('v1' => 'x', // 'v2' => 'y', // ); // (Default: array() ) // (in) array $special_fields // Assoc array of assoc arrays to offer more // than what is in a DESC of $table. e.g. // If you want to rename the options for the fields // in a certain enum you could do this: // $choice_fields = array( // 'gender' => array( // 'M' => 'Male', // 'F' => 'Female', // 'O' => 'Other' // ) // ); // Note: that I'm spelling out the options for // 'gender' and adding a new option. // (Default: array() ) // Return Values: // string PHP Code. // Remarks: // Remeber to eval the result // // Fields in the table end in "_id" are not shown, i.e. we // don't want users to be able to update keys. // // $input['next_action'] produces the form buttons and may // have to be added to $input before calling AutoForm. // -------------------------------------------------------- function AutoForm($input, $table_name, $radio=0, $action="", $explicit_label=array(), $hidden_fields=array(), $hidden_vars=array(), $choice_fields=array() ) { $code = "\$html = \"\";\n"; if (empty($action)) { $action = $_SERVER['SCRIPT_NAME']; } $field_list = TableFields($table_name); if (empty($field_list)) { return; } $code .= "\$html .= StartForm(\"$action\", array('method' => 'post'));\n"; // hidden variables $code .= "\$html .= HiddenField(\"table_name\", \"$table_name\");\n"; if (count($hidden_vars)) { $hidden = ""; foreach ($hidden_vars as $key => $value) { $hidden .= "\$html .= HiddenField(\"$key\", \"$value\");\n"; } $code .= $hidden; } // start printing form $code .= "\$html .= StartFormTable();\n"; foreach($field_list as $field_name => $field_type) { if (array_key_exists($field_name, $explicit_label)) { $label = $explicit_label[$field_name]; } else { $label = ucwords(ereg_replace("_", " ", $field_name)); } if (array_key_exists($field_name, $choice_fields)) { // pseudo-enum if ($radio) { $menu = ""; foreach ($choice_fields[$field_name] as $key => $value) { $menu .= "\t"; $menu .= "RadioField(\"$field_name\", \"$key\", \"$value\", " . "\"" . $input[$field_name] . "\"" . ")"; $menu .= " . \n"; // want them concatenated } $menu = substr($menu, 0, -4); // trim last " . \n" } else { $menu = "SelectField(\"$field_name\", "; $menu .= ArrayToString($choice_fields[$field_name]) . ", "; $menu .= "\"" . $input[$field_name] . "\"" . ")\n"; } $code .= "\$html .= FormRow(\"$label\", $menu);\n"; continue; } if (in_array($field_name, $hidden_fields)) { $code .= "\$html .= HiddenField($field_name, \$input['" . $field_name . "']);\n"; continue; } elseif (eregi("_id$", $field_name)) { if (!empty($input[$field_name])) { $code .= "\$html .= HiddenField($field_name, \$input['" . $field_name . "']);\n"; } continue; } elseif (eregi("timestamp", $field_type)) { continue; } $code .= "\$html .= FormRow(\"$label\", \n"; $code .= "\t"; $code .= FormField($field_name, $field_type, $input[$field_name], $input, $radio); $code .= ");\n"; } // close foreach if (!empty($input['next_action'])) { if (is_array($input['next_action'])) { foreach($input['next_action'] as $next_action) { $buttons .= "SubmitField(\"action\", $next_action);\n"; } } else { $buttons .= "SubmitField(\"action\", " . "\"" . $input['next_action'] . "\"" . ")\n"; } $code .= "\$html .= FormRow(\"\", $buttons);\n"; } $code .= "\$html .= EndFormTable();\n"; $code .= "\$html .= EndForm();\n"; $code .= "return \$html;\n"; return $code; } // -------------------------------------------------------- // Function: ArrayToString // Description: Change an array to a string // representing an array // Type: public // Parameters: // [in] array An array to convert to a string // Return Values: // string The definition of an assoc array // Remarks: // None // -------------------------------------------------------- function ArrayToString($list) { $arr_str = "array( \n"; foreach($list as $item) { $item = trim($item); $arr_str .= "\"$item\" => \"$item\", \n"; } $arr_str = substr($arr_str, 0, -3); // trim last ", \n" $arr_str .= ")\n"; return $arr_str; } // -------------------------------------------------------- // Function: EnumList // Description: break apart an SQL enum definition // into an array declaration of values // Type: public // Parameters: // [in] string $enum_string // An SQL enum definition // e.g. "enum('M', 'F')" // Return Values: // string The definition of an assoc array // Remarks: // Given the following: // $sql = "enum('a', 'b', 'c')"; // $enum_list = EnumList($sql); // $enum_list_code = "\$enum_list = $enum_list" . ";"; // eval($enum_list_code); // print_r($enum_list); // We would see the following: // Array // ( // [a] => a // [b] => b // [c] => c // ) // -------------------------------------------------------- function EnumList($enum_string) { $list = explode(',', ereg_replace("[)']", '', str_replace('enum(', '', $enum_string))); return ArrayToString($list); } // -------------------------------------------------------- // Function: TableFields // Description: Returns an assoc array representing // a DESC of a table // Type: public // Parameters: // [in] string $table_name // The table that will be DESC'd // Return Values: // array array of field_name->field_type defining // fields in table $table_name // Remarks: // None // -------------------------------------------------------- function TableFields($table_name) { $sql = "DESCRIBE " . $table_name; $result = mysql_query($sql) or die(mysql_error()); $namelist = array(); while ($row = mysql_fetch_array($result)) { $namelist[$row['Field']] = $row['Type']; } return $namelist; } // -------------------------------------------------------- // Function: GetKey // Description: Gets the key of a table // Type: public // Parameters: // [in] string $talbe_name // The table we want the key of // Return Values: // string the field name of the key // Remarks: // None // -------------------------------------------------------- function GetKey($table_name) { static $known_keys = array(); // save previous results; assumes defs static if (array_key_exists($table_name, $known_keys)) { return $known_keys[$table_name]; } $sql = "SHOW INDEX FROM $table_name"; $result = mysql_query($sql) or die(mysql_error()); if (mysql_num_rows($result) < 1) { return NULL; } if (mysql_num_rows($result) == 1) { $row = mysql_fetch_array($result); $know_keys[$table_name] = $row['Column_name']; return $row['Column_name']; } while ($row = mysql_fetch_array($result)) { if ($row['Key_name'] == 'PRIMARY') { $know_keys[$table_name] = $row['Column_name']; return $row['Column_name']; } } // if no primary key out of several, return first index reset($result); $row = mysql_fetch_array($result); $know_keys[$table_name] = $row['Column_name']; return $row['Column_name']; } // -------------------------------------------------------- // Function: FormField // Description: Shows calls to functions in forms.php // Type: public // Parameters: // [in] string $field_name // The name of the field // [in] string $field_type // The MySQL field type // [in] string $field_value // The current value of the field // (in) array $input An associative array of inputs // normally $_GET or $_POST passed // to maintain state // (Default: NULL) // (in) boolean $radio By default HTML SelectFields // AKA "pull-downs" are used for enums. // If this is field is true the // form will have radio buttons // instead // (Default: False) // Return Values: // None // Remarks: // This is a variation of FormField to show the middle code // for further modification. The AutoForm can be a great // starting point but sometimes its output is to rigid looking // To copy the HTML produced by it for modification would be // to lock ourselves into a low level language that wouldn't // scale well. What I want to see is the calls to functions // in the forms.php library. This prints those calls. It is // a code generator to build on. If this were Lisp I would // have just printed instead of evaluating sharp-quoted calls. // // Calls functions from forms.php based on what it is passed // Need $input for maintaining date information // -------------------------------------------------------- function FormField($field_name, $field_type, $field_value, $input=NULL, $radio=0) { list($type, $length) = sscanf(ereg_replace("[()]", " ", $field_type), "%s %d"); // Quote some values (don't want them evaluated) // set future field values to be based on $input (which will be set to GET or POST) $field_value = "\$input['$field_name']"; // done here before $field_name is updated $field_name = "\"$field_name\""; switch($type) { case 'char': case 'varchar': if ($length > 10) { $field_length = 60; } else { $field_length = $length; } return "TextField($field_name, $field_value, $field_length, $length)"; case 'date': if (!count($input)) $arr = "\$input"; else $arr = "\$_REQUEST"; return "DateForm($field_name, $arr)"; case 'integer': case 'int': if (empty($length)) { $field_length = $length = 10; } else { $field_length = $length; } return "TextField($field_name, $field_value, $field_length, $length)"; case 'tinyint': case 'bit': case 'bool': case 'boolean': return "CheckboxField($field_name, 1, \"(check here)\", $field_value)"; case 'text': return "TextareaField($field_name, $field_value, 80, 8, \"hard\" )"; case 'timestamp': return ""; // don't do anything for timestamp case 'enum': $enum_list = EnumList($field_type); if ($radio) { $html = ""; $enum_list_code = "\$enum_list = $enum_list" . ";"; // want to actualize array now eval($enum_list_code); foreach ($enum_list as $key => $value) { $html .= "\t"; $html .= "RadioField($field_name, \"$key\", \"$value\", $field_value)"; $html .= " . \n"; // want them concatenated } return substr($html, 0, -4); // trim last " . \n" } else { return "SelectField($field_name, $enum_list, $field_value)"; } default: return "\"Unsupported DB Field Type: $type\""; } // close switch } ?>