forms.inc

File

includes/forms.inc
View source
  1. <?php
  2. /*
  3. * This include file contains functions pertaining to the
  4. * creation of forms through FlightPath's form API
  5. */
  6. /**
  7. * This function gets the form array, where the callback is the same as form_id.
  8. * It will also look for modules which may want to alter the form, using hook_form_alter,
  9. * and go ahead and apply that.
  10. *
  11. * It will also reorder the elements by weight.
  12. *
  13. */
  14. function fp_get_form($form_id, $params = array()) {
  15. $form = call_user_func_array($form_id, $params);
  16. // Add in the default submit_handlers and validate_handlers, if not all ready set.
  17. if (!isset($form["#submit_handlers"])) $form["#submit_handlers"] = array($form_id . "_submit");
  18. if (!isset($form["#validate_handlers"])) $form["#validate_handlers"] = array($form_id . "_validate");
  19. $modules = modules_implement_hook("form_alter");
  20. foreach ($modules as $module) {
  21. call_user_func_array($module . '_form_alter', array(&$form, $form_id));
  22. }
  23. // Okay, now the fun part. Re-order the elements by weight. Lighter weights
  24. // should float to the top. Elements w/o a weight listed are assumed to have a weight of 0.
  25. // Unfortunately we cannot use uasort, as it re-orders our indexes when weights are identical.
  26. // The first the I want to do is find out, what are the defined weights in this form, if any.
  27. $defined_weights = array();
  28. foreach ($form as $element) {
  29. $weight = (int)$element["weight"];
  30. if (!in_array($weight, $defined_weights)) {
  31. $defined_weights[] = $weight;
  32. }
  33. }
  34. // Okay, now sort our weights.
  35. sort($defined_weights);
  36. // Before we get to assigning weights, we need to make sure
  37. // that none of our form elements have a name which might cause us trouble.
  38. // Namely, no element can be named "submit" (like a button) because it will
  39. // interfere with our javascript functions.
  40. $form2 = array();
  41. foreach ($form as $key => $element) {
  42. $name = $key;
  43. if ($name == "submit") {
  44. $name = "btn_submit";
  45. }
  46. $form2[$name] = $element;
  47. }
  48. $form = $form2;
  49. // Okay, now go through the weights and create a new form in THAT order.
  50. $new_form = array();
  51. foreach ($defined_weights as $dw) {
  52. foreach ($form as $key => $element) {
  53. $weight = (int)$element["weight"];
  54. if ($weight == $dw) {
  55. $new_form[$key] = $element;
  56. }
  57. }
  58. }
  59. // Okay, we should now be good to go!
  60. return $new_form;
  61. }
  62. /**
  63. * This function is meant to be used by the uasort command, to help re-order
  64. * a form array based on each element's weight value. If weight is blank, it is assumed
  65. * to be 0 (zero).
  66. *
  67. * Answers the question "is A LESS THAN b?"
  68. * with: -1 == true. 0 == they are equal. 1 = no, b is less than a.
  69. *
  70. */
  71. function form_field_sort_compare_by_weight($element_a, $element_b) {
  72. if (!is_array($element_a) || !is_array($element_b)) {
  73. return 0;
  74. }
  75. $weight_a = $element_a["weight"]*1;
  76. $weight_b = $element_b["weight"]*1;
  77. if ($weight_a == $weight_b) return -1;
  78. return ($weight_a < $weight_b) ? -1 : 1;
  79. }
  80. /**
  81. * Render the form array from the callback to the screen, and
  82. * set the form to save itself in our default submit handler.
  83. * Valid form_types are:
  84. * "system_settings" => values automatically saved to variables table.
  85. * "normal" or BLANK => values are forwarded to $callback_submit() function, if it exists.
  86. */
  87. function fp_render_form($callback, $form_type = "") {
  88. global $current_student_id, $user;
  89. $rtn = "";
  90. // Were there extra params after callback and form_type? Wrap them up
  91. // and send them along to fp_get_form
  92. $params = array();
  93. if (func_num_args() > 2) {
  94. // Remove first 2 arguments, so all we have left is what the user added to it.
  95. $params = func_get_args();
  96. array_shift($params);
  97. array_shift($params);
  98. }
  99. $form = fp_get_form($callback, $params);
  100. // Figure out the current page's title and display it.
  101. $path = $_GET["q"];
  102. $default_path = $path;
  103. // Figure out the "default_query" from $_GET
  104. $new_query = array();
  105. foreach ($_GET as $key => $val) {
  106. if ($key != "q") {
  107. $new_query[] = "$key=$val";
  108. }
  109. }
  110. if (count($new_query)) {
  111. $default_query = join("&", $new_query);
  112. }
  113. $page_title = $GLOBALS["fp_current_menu_router_item"]["title"];
  114. if (isset($GLOBALS["fp_set_title"])) {
  115. $page_title = $GLOBALS["fp_set_title"];
  116. }
  117. if ($page_title != "") {
  118. $rtn .= "<h2 class='title'>" . $page_title . "</h2>";
  119. }
  120. //fpm($GLOBALS["fp_current_menu_router_item"]);
  121. $form_path = $GLOBALS["fp_current_menu_router_item"]["path"];
  122. // Are there any files required to get to the submit handler for this form?
  123. $form_include = "";
  124. // Set the form_include to the current page's "file" requirement, if any.
  125. if (is_array($GLOBALS["fp_current_menu_router_item"])) {
  126. if (isset($GLOBALS["fp_current_menu_router_item"]["file"])) {
  127. $form_include = $GLOBALS["fp_current_menu_router_item"]["file"];
  128. }
  129. }
  130. if ($form["#form_include"]) {
  131. $form_include = $form["#form_include"];
  132. }
  133. $extra_form_class = "";
  134. if ($form_type == "system_settings") {
  135. $extra_form_class = "fp-system-form";
  136. }
  137. $form_token = md5($callback . fp_token());
  138. // Set up our form's attributes.
  139. $attributes = $form["#attributes"];
  140. if (!is_array($attributes)) $attributes = array();
  141. $attributes["class"] .= " $extra_form_class fp-form fp-form-$callback ";
  142. // Convert the attributes array into a string.
  143. $new_attr = "";
  144. foreach ($attributes as $key => $val) {
  145. $new_attr .= " $key='$val' ";
  146. }
  147. $attributes = $new_attr;
  148. // Did the user specify a submit method (like GET or POST)? POST is default.
  149. $submit_method = ($form["#submit_method"] == "") ? "POST" : $form["#submit_method"];
  150. $rtn .= "<form action='" . base_path() . "/system-handle-form-submit' method='$submit_method' id='fp-form-$callback' name='fp_form_name_$callback' $attributes>";
  151. $rtn .= "<input type='hidden' name='callback' value='$callback'>";
  152. $rtn .= "<input type='hidden' name='form_token' value='$form_token'>";
  153. $rtn .= "<input type='hidden' name='form_type' value='$form_type'>";
  154. $rtn .= "<input type='hidden' name='form_path' value='$form_path'>";
  155. $rtn .= "<input type='hidden' name='form_include' value='$form_include'>";
  156. $rtn .= "<input type='hidden' name='default_redirect_path' value='$default_path'>";
  157. $rtn .= "<input type='hidden' name='default_redirect_query' value='$default_query'>";
  158. //$rtn .= "<input type='hidden' name='redirect_query' value='$redirect_query'>";
  159. $rtn .= "<input type='hidden' name='current_student_id' value='$current_student_id'>";
  160. $use_callback = "";
  161. if (form_has_errors()) {
  162. // We will only pull previous POST's values if there are errors on the form.
  163. $use_callback = $callback;
  164. }
  165. foreach ($form as $name => $element) {
  166. if (is_array($element) && (isset($element["type"]) || isset($element["value"]))) {
  167. $rtn .= fp_render_form_element($name, $element, $use_callback);
  168. }
  169. }
  170. // If this is a system settings form, go ahead and display the save button.
  171. if ($form_type == "system_settings") {
  172. $rtn .= "<div class='buttons'>";
  173. //$rtn .= fp_render_button("Save settings", "\$(\"#sysform\").submit()");
  174. $rtn .= "<input type='submit' name='submit_button' value='" . t("Save settings") . "'>";
  175. $rtn .= "</div>";
  176. }
  177. $rtn .= "</form>";
  178. // Clear any existing form errors and values
  179. unset($_SESSION["fp_form_errors"]);
  180. clear_session_form_values($callback);
  181. return $rtn;
  182. }
  183. /**
  184. * Clear the form submissions variable from the SESSION for this callback.
  185. */
  186. function clear_session_form_values($callback) {
  187. unset($_SESSION["fp_form_submissions"][$callback]);
  188. }
  189. /**
  190. * This is a very basic valiator for form API submission.
  191. * All I really care about is making sure required fields have
  192. * a value in them. If they do not, we will file a form_error.
  193. */
  194. function form_basic_validate($form, $form_submitted) {
  195. foreach ($form as $name => $element) {
  196. if (is_array($element) && $element["required"]) {
  197. // Okay, this is a required field. So, check that it has a non-blank value
  198. // in form_submitted.
  199. if ($form_submitted["values"][$name] == "") {
  200. // It's blank! ERROR!
  201. $label = $element["label"];
  202. if ($label == "") $label = $name;
  203. form_error($name, t("You must enter a value for <b>%element_label</b>", array("%element_label" => $label)));
  204. }
  205. }
  206. }
  207. }
  208. /**
  209. * Register a form_error in the SESSION.
  210. */
  211. function form_error($element_name, $message) {
  212. $_SESSION["fp_form_errors"][] = array("name" => $element_name, "msg" => $message);
  213. fp_add_message($message, "error");
  214. }
  215. /**
  216. * Returns TRUE or FALSE if there have been errors for this form submission
  217. * (We will just look in the SESSION to find out).
  218. */
  219. function form_has_errors() {
  220. if (count($_SESSION["fp_form_errors"]) > 0) {
  221. return TRUE;
  222. }
  223. return FALSE;
  224. }
  225. /**
  226. * Returns the HTML to render this form element to the screen.
  227. * $name is the HTML machine name. $element is an array containing all we need to render it.
  228. * If you want default values to be taken from the SESSION (because we had form_errors, say, and we
  229. * want values to keep what we had between submissions) specify the callback to use in the
  230. * use_session_submission_values_for_callback variable.
  231. */
  232. function fp_render_form_element($name, $element, $use_session_submission_values_for_callback = "") {
  233. $rtn = "";
  234. $type = $element["type"];
  235. if ($type == "") $type = "markup";
  236. $value = $element["value"];
  237. $label = $element["label"];
  238. $options = $element["options"];
  239. $description = $element["description"];
  240. $popup_description = $element["popup_description"];
  241. $prefix = $element["prefix"];
  242. $suffix = $element["suffix"];
  243. $required = $element["required"];
  244. $no_please_select = $element["no_please_select"];
  245. if (isset($element["hide_please_select"])) {
  246. $no_please_select = $element["hide_please_select"];
  247. }
  248. $confirm = $element["confirm"];
  249. $attributes = $element["attributes"];
  250. if (is_array($attributes)) {
  251. // Convert the attributes array into a string.
  252. $new_attr = "";
  253. foreach ($attributes as $key => $val) {
  254. $new_attr .= " $key='$val' ";
  255. }
  256. $attributes = $new_attr;
  257. }
  258. $popup_help_link = "";
  259. if ($popup_description) {
  260. //$popup_help_link = " <a href='javascript: alert(\"" . $popup_description . "\");' class='form-popup-description'>[?]</a>";
  261. $popup_help_link = fp_get_js_alert_link($popup_description, "[?]", "form-popup-description");
  262. }
  263. $element_extra_css = "";
  264. if (is_array($_SESSION["fp_form_errors"])) {
  265. foreach ($_SESSION["fp_form_errors"] as $err) {
  266. if ($err["name"] == $name) {
  267. // There is an error on this element! Add an extra CSS element.
  268. $element_extra_css .= "form-element-error";
  269. }
  270. }
  271. }
  272. if ($use_session_submission_values_for_callback && is_array($_SESSION["fp_form_submissions"][$use_session_submission_values_for_callback]["values"])) {
  273. // Check the SESSION for a previous value which we should use.
  274. $ignore_types = array("hidden", "markup", "submit", "password");
  275. if (!in_array($type, $ignore_types)) {
  276. $value = $_SESSION["fp_form_submissions"][$use_session_submission_values_for_callback]["values"][$name];
  277. }
  278. }
  279. if ($type != "markup") {
  280. $rtn .= "<div id='element-wrapper-$name' class='form-element element-type-$type $element_extra_css'>";
  281. }
  282. if ($prefix) {
  283. $rtn .= $prefix;
  284. }
  285. $ast = "";
  286. if ($required) {
  287. $ast = "<span class='form-required-ast'>*</span>";
  288. }
  289. // First of all, what is it's "type"?
  290. if ($type == "markup") {
  291. $rtn .= "$value";
  292. }
  293. else if ($type != "hidden" && $type != "checkbox") {
  294. $rtn .= "<label>$ast$label $popup_help_link</label>";
  295. }
  296. if ($type == "textarea") {
  297. $rows = ($element["rows"]) ? $element["rows"] : "5";
  298. $rtn .= "<textarea name='$name' id='element-$name' rows='$rows' $attributes>$value</textarea>";
  299. }
  300. if ($type == "textfield" || $type == "text" || $type == "password") {
  301. if ($type == "textfield") $type = "text";
  302. $size = ($element["size"]) ? $element["size"] : "60";
  303. $maxlength = ($element["maxlength"]) ? $element["maxlength"] : "255";
  304. $value = htmlentities($value, ENT_QUOTES);
  305. $rtn .= "<input type='$type' name='$name' id='element-$name' size='$size' maxlength='$maxlength' value='$value' $attributes>";
  306. }
  307. if ($type == "hidden") {
  308. $value = htmlentities($value, ENT_QUOTES);
  309. $rtn .= "<input type='hidden' name='$name' id='element-$name' value='$value'>";
  310. }
  311. if ($type == "file") {
  312. $rtn .= "<input type='file' name='$name' id='element-$name'>";
  313. }
  314. if ($type == "radios") {
  315. $rtn .= "<div class='form-radios form-radios-$name'>";
  316. foreach ($options as $key => $val) {
  317. $checked = "";
  318. if ($value == $key) {
  319. $checked = "checked=checked";
  320. }
  321. $rtn .= "<div class='radio-element radio-element-$key'>
  322. <label class='label-for-radio'><input type='radio' name='$name' id='element-$name-$key' value='$key' $checked $attributes> $val</label>
  323. </div>";
  324. }
  325. $rtn .= "</div>";
  326. }
  327. if ($type == "select") {
  328. $rtn .= "<select name='$name' id='element-$name' $attributes>";
  329. if ($no_please_select != TRUE) {
  330. $rtn .= "<option value=''>- Please select -</option>";
  331. }
  332. foreach ($options as $key => $val) {
  333. $selected = "";
  334. if ($value == $key) {
  335. $selected = "selected";
  336. }
  337. $rtn .= "<option value='$key' $selected>$val</option>";
  338. }
  339. $rtn .= "</select>";
  340. }
  341. // Multiple checkboxes...
  342. if ($type == "checkboxes") {
  343. $rtn .= "<div class='form-checkboxes form-checkboxes-$name'>";
  344. foreach ($options as $key => $val) {
  345. $checked = "";
  346. if (is_array($value) && $value[$key] == $key) {
  347. $checked = "checked=checked";
  348. }
  349. $rtn .= "<div class='checkbox-element checkbox-element-$key'>
  350. <label class='label-for-checkbox'><input type='checkbox' name='$name" . "[$key]' id='element-$name-$key' value='$key' $checked $attributes> $val</label>
  351. </div>";
  352. }
  353. $rtn .= "</div>";
  354. }
  355. // A single checkbox... The values will be with 0 (zero) or 1 (one), and boolean
  356. // values are accepted/saved
  357. if ($type == "checkbox") {
  358. $rtn .= "<div class='form-checkbox form-checkbox-$name'>";
  359. $checked = "";
  360. if ((bool)($value) == TRUE) {
  361. $checked = "checked=checked";
  362. }
  363. $rtn .= "<div class='checkbox-element'>
  364. <label class='label-for-checkbox'><input type='checkbox' name='$name' id='element-$name' value='1' $checked $attributes> $label</label>
  365. </div>";
  366. $rtn .= "</div>";
  367. }
  368. if ($type == "submit") {
  369. if ($confirm != "") {
  370. $confirm = htmlentities($confirm, ENT_QUOTES);
  371. $confirm = str_replace("\n", "\\n", $confirm);
  372. $attributes .= " onClick='return confirm(\"$confirm\");' ";
  373. }
  374. $rtn .= "<input type='submit' name='$name' value='$value' $attributes>";
  375. }
  376. if ($type == "button") {
  377. $rtn .= "<input type='button' name='$name' value='$value' $attributes>";
  378. }
  379. if ($description) {
  380. $rtn .= "<div class='form-element-description'>$description</div>";
  381. }
  382. if ($suffix) {
  383. $rtn .= $suffix;
  384. }
  385. if ($type != "markup") {
  386. $rtn .= "</div>";
  387. }
  388. return $rtn;
  389. }

Functions

Namesort descending Description
clear_session_form_values Clear the form submissions variable from the SESSION for this callback.
form_basic_validate This is a very basic valiator for form API submission. All I really care about is making sure required fields have a value in them. If they do not, we will file a form_error.
form_error Register a form_error in the SESSION.
form_field_sort_compare_by_weight This function is meant to be used by the uasort command, to help re-order a form array based on each element's weight value. If weight is blank, it is assumed to be 0 (zero).
form_has_errors Returns TRUE or FALSE if there have been errors for this form submission (We will just look in the SESSION to find out).
fp_get_form This function gets the form array, where the callback is the same as form_id. It will also look for modules which may want to alter the form, using hook_form_alter, and go ahead and apply that.
fp_render_form Render the form array from the callback to the screen, and set the form to save itself in our default submit handler. Valid form_types are: "system_settings" => values automatically saved to variables table. "normal" or BLANK…
fp_render_form_element Returns the HTML to render this form element to the screen. $name is the HTML machine name. $element is an array containing all we need to render it. If you want default values to be taken from the SESSION (because we had form_errors, say, and…