form_example_wizard.inc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. <?php
  2. /**
  3. * @file
  4. * Extensible wizard form example.
  5. */
  6. /**
  7. * Extensible wizard form example.
  8. *
  9. * This is an example of a multistep form using a wizard style. It will include
  10. * the 'Previous' and 'Next' buttons when required, and a 'Finish' button at the
  11. * last stage of the form submission.
  12. *
  13. * This example is an extensible skeleton that can include (even
  14. * programmatically) more steps. The demonstration form includes three steps,
  15. * each step having its own validation functions.
  16. *
  17. * How to extend this example:
  18. * - Steps are defined in the _form_example_steps() function. Include or alter
  19. * the steps as you require.
  20. * - For each step, implement the corresponding 'form' function (see
  21. * 'form_example_wizard_personal_info' for the first step in this example.)
  22. * Each step is a regular form, and the wizard collects all the values of the
  23. * included forms.
  24. * - Optionally, you may include custom validation functions using the regular
  25. * validation hook (formname_validate). The wizard uses these validation
  26. * functions for each step.
  27. * - The most important customization step is to change the submit handler and
  28. * do whatever you want with the collected information. In this case, the
  29. * example just shows the collected values in the various steps.
  30. * @ingroup form_example
  31. */
  32. /**
  33. * Returns the list of steps and their associated forms.
  34. *
  35. * This has been separated to clarify and easy the understanding of this
  36. * example. You should edit this function to include the steps your
  37. * wizard/multistep form requires.
  38. *
  39. * @return array
  40. * List of steps and their forms.
  41. *
  42. * @ingroup form_example
  43. */
  44. function _form_example_steps() {
  45. return array(
  46. 1 => array(
  47. 'form' => 'form_example_wizard_personal_info',
  48. ),
  49. 2 => array(
  50. 'form' => 'form_example_wizard_location_info',
  51. ),
  52. 3 => array(
  53. 'form' => 'form_example_wizard_other_info',
  54. ),
  55. );
  56. }
  57. /**
  58. * The primary formbuilder function for the wizard form.
  59. *
  60. * This is the form that you should call with drupal_get_form() from your code,
  61. * and it will include the rest of the step forms defined. You are not required
  62. * to change this function, as this will handle all the step actions for you.
  63. *
  64. * This form has two defined submit handlers to process the different steps:
  65. * - Previous: handles the way to get back one step in the wizard.
  66. * - Next: handles each step form submission,
  67. *
  68. * The third handler, the finish button handler, is the default form_submit
  69. * handler used to process the information.
  70. *
  71. * You are not required to change the next or previous handlers, but you must
  72. * change the form_example_wizard_submit handler to perform the operations you
  73. * need on the collected information.
  74. *
  75. * @ingroup form_example
  76. */
  77. function form_example_wizard($form, &$form_state) {
  78. // Initialize a description of the steps for the wizard.
  79. if (empty($form_state['step'])) {
  80. $form_state['step'] = 1;
  81. // This array contains the function to be called at each step to get the
  82. // relevant form elements. It will also store state information for each
  83. // step.
  84. $form_state['step_information'] = _form_example_steps();
  85. }
  86. $step = &$form_state['step'];
  87. drupal_set_title(t('Extensible Wizard: Step @step', array('@step' => $step)));
  88. // Call the function named in $form_state['step_information'] to get the
  89. // form elements to display for this step.
  90. $form = $form_state['step_information'][$step]['form']($form, $form_state);
  91. // Show the 'previous' button if appropriate. Note that #submit is set to
  92. // a special submit handler, and that we use #limit_validation_errors to
  93. // skip all complaints about validation when using the back button. The
  94. // values entered will be discarded, but they will not be validated, which
  95. // would be annoying in a "back" button.
  96. if ($step > 1) {
  97. $form['prev'] = array(
  98. '#type' => 'submit',
  99. '#value' => t('Previous'),
  100. '#name' => 'prev',
  101. '#submit' => array('form_example_wizard_previous_submit'),
  102. '#limit_validation_errors' => array(),
  103. );
  104. }
  105. // Show the Next button only if there are more steps defined.
  106. if ($step < count($form_state['step_information'])) {
  107. // The Next button should be included on every step.
  108. $form['next'] = array(
  109. '#type' => 'submit',
  110. '#value' => t('Next'),
  111. '#name' => 'next',
  112. '#submit' => array('form_example_wizard_next_submit'),
  113. );
  114. }
  115. else {
  116. // Just in case there are no more steps, we use the default submit handler
  117. // of the form wizard. Call this button Finish, Submit, or whatever you
  118. // want to show. When this button is clicked, the
  119. // form_example_wizard_submit handler will be called.
  120. $form['finish'] = array(
  121. '#type' => 'submit',
  122. '#value' => t('Finish'),
  123. );
  124. }
  125. // Include each validation function defined for the different steps.
  126. if (function_exists($form_state['step_information'][$step]['form'] . '_validate')) {
  127. $form['next']['#validate'] = array($form_state['step_information'][$step]['form'] . '_validate');
  128. }
  129. return $form;
  130. }
  131. /**
  132. * Submit handler for the "previous" button.
  133. *
  134. * This function:
  135. * - Stores away $form_state['values']
  136. * - Decrements the step counter
  137. * - Replaces $form_state['values'] with the values from the previous state.
  138. * - Forces form rebuild.
  139. *
  140. * You are not required to change this function.
  141. *
  142. * @ingroup form_example
  143. */
  144. function form_example_wizard_previous_submit($form, &$form_state) {
  145. $current_step = &$form_state['step'];
  146. $form_state['step_information'][$current_step]['stored_values'] = $form_state['input'];
  147. if ($current_step > 1) {
  148. $current_step--;
  149. $form_state['values'] = $form_state['step_information'][$current_step]['stored_values'];
  150. }
  151. $form_state['rebuild'] = TRUE;
  152. }
  153. /**
  154. * Submit handler for the 'next' button.
  155. *
  156. * This function:
  157. * - Saves away $form_state['values']
  158. * - Increments the step count.
  159. * - Replace $form_state['values'] from the last time we were at this page
  160. * or with array() if we haven't been here before.
  161. * - Force form rebuild.
  162. *
  163. * You are not required to change this function.
  164. *
  165. * @ingroup form_example
  166. */
  167. function form_example_wizard_next_submit($form, &$form_state) {
  168. $current_step = &$form_state['step'];
  169. $form_state['step_information'][$current_step]['stored_values'] = $form_state['values'];
  170. if ($current_step < count($form_state['step_information'])) {
  171. $current_step++;
  172. if (!empty($form_state['step_information'][$current_step]['stored_values'])) {
  173. $form_state['values'] = $form_state['step_information'][$current_step]['stored_values'];
  174. }
  175. else {
  176. $form_state['values'] = array();
  177. }
  178. // Force rebuild with next step.
  179. $form_state['rebuild'] = TRUE;
  180. return;
  181. }
  182. }
  183. /**
  184. * The previous code was a 'skeleton' of a multistep wizard form. You are not
  185. * required to change a line on the previous code (apart from defining your own
  186. * steps in the _form_example_steps() function.
  187. *
  188. * All the code included from here is the content of the wizard, the steps of
  189. * the form.
  190. *
  191. * First, let's show the defined steps for the wizard example.
  192. * @ingroup form_example
  193. */
  194. /**
  195. * Returns form elements for the 'personal info' page of the wizard.
  196. *
  197. * This is the first step of the wizard, asking for two textfields: first name
  198. * and last name.
  199. *
  200. * @ingroup form_example
  201. */
  202. function form_example_wizard_personal_info($form, &$form_state) {
  203. $form = array();
  204. $form['first_name'] = array(
  205. '#type' => 'textfield',
  206. '#title' => t('First Name'),
  207. '#default_value' => !empty($form_state['values']['first_name']) ? $form_state['values']['first_name'] : '',
  208. );
  209. $form['last_name'] = array(
  210. '#type' => 'textfield',
  211. '#title' => t('Last Name'),
  212. '#default_value' => !empty($form_state['values']['last_name']) ? $form_state['values']['last_name'] : '',
  213. );
  214. return $form;
  215. }
  216. /**
  217. * Returns form elements for the 'location info' page of the wizard.
  218. *
  219. * This is the second step of the wizard. This step asks for a textfield value:
  220. * a City. This step also includes a validation declared later.
  221. *
  222. * @ingroup form_example
  223. */
  224. function form_example_wizard_location_info($form, &$form_state) {
  225. $form = array();
  226. $form['city'] = array(
  227. '#type' => 'textfield',
  228. '#title' => t('City'),
  229. '#description' => t('Hint: Do not enter "San Francisco", and do not leave this out.'),
  230. '#required' => TRUE,
  231. '#default_value' => !empty($form_state['values']['city']) ? $form_state['values']['city'] : '',
  232. );
  233. return $form;
  234. }
  235. /**
  236. * Custom validation form for the 'location info' page of the wizard.
  237. *
  238. * This is the validation function for the second step of the wizard.
  239. * The city cannot be empty or be "San Francisco".
  240. *
  241. * @ingroup form_example
  242. */
  243. function form_example_wizard_location_info_validate($form, &$form_state) {
  244. if ($form_state['values']['city'] == 'San Francisco') {
  245. form_set_error('city', t('You were warned not to enter "San Francisco"'));
  246. }
  247. }
  248. /**
  249. * Returns form elements for the 'other info' page of the wizard.
  250. *
  251. * This is the third and last step of the example wizard.
  252. *
  253. * @ingroup form_example
  254. */
  255. function form_example_wizard_other_info($form, &$form_state) {
  256. $form = array();
  257. $form['aunts_name'] = array(
  258. '#type' => 'textfield',
  259. '#title' => t("Your first cousin's aunt's Social Security number"),
  260. '#default_value' => !empty($form_state['values']['aunts_name']) ? $form_state['values']['aunts_name'] : '',
  261. );
  262. return $form;
  263. }
  264. /**
  265. * Wizard form submit handler.
  266. *
  267. * This function:
  268. * - Saves away $form_state['values']
  269. * - Process all the form values.
  270. *
  271. * And now comes the magic of the wizard, the function that should handle all
  272. * the inputs from the user on each different step.
  273. *
  274. * This demonstration handler just do a drupal_set_message() with the
  275. * information collected on each different step of the wizard.
  276. *
  277. * @ingroup form_example
  278. */
  279. function form_example_wizard_submit($form, &$form_state) {
  280. $current_step = &$form_state['step'];
  281. $form_state['step_information'][$current_step]['stored_values'] = $form_state['values'];
  282. // In this case we've completed the final page of the wizard, so process the
  283. // submitted information.
  284. drupal_set_message(t('This information was collected by this wizard:'));
  285. foreach ($form_state['step_information'] as $index => $value) {
  286. // Remove FAPI fields included in the values (form_token, form_id and
  287. // form_build_id. This is not required, you may access the values using
  288. // $value['stored_values'] but I'm removing them to make a more clear
  289. // representation of the collected information as the complete array will
  290. // be passed through drupal_set_message().
  291. unset($value['stored_values']['form_id']);
  292. unset($value['stored_values']['form_build_id']);
  293. unset($value['stored_values']['form_token']);
  294. // Now show all the values.
  295. drupal_set_message(t('Step @num collected the following values: <pre>@result</pre>',
  296. array(
  297. '@num' => $index,
  298. '@result' => print_r($value['stored_values'], TRUE),
  299. )
  300. ));
  301. }
  302. }