| Drupal | PHP Cross Reference | Content Management Systems |
1 <?php 2 /** 3 * @file 4 * Functions for form and batch generation and processing. 5 */ 6 7 /** 8 * @defgroup forms Form builder functions 9 * @{ 10 * Functions that build an abstract representation of a HTML form. 11 * 12 * All modules should declare their form builder functions to be in this 13 * group and each builder function should reference its validate and submit 14 * functions using \@see. Conversely, validate and submit functions should 15 * reference the form builder function using \@see. For examples, of this see 16 * system_modules_uninstall() or user_pass(), the latter of which has the 17 * following in its doxygen documentation: 18 * 19 * \@ingroup forms 20 * \@see user_pass_validate(). 21 * \@see user_pass_submit(). 22 * 23 * @} 24 */ 25 26 /** 27 * @defgroup form_api Form generation 28 * @{ 29 * Functions to enable the processing and display of HTML forms. 30 * 31 * Drupal uses these functions to achieve consistency in its form processing and 32 * presentation, while simplifying code and reducing the amount of HTML that 33 * must be explicitly generated by modules. 34 * 35 * The primary function used with forms is drupal_get_form(), which is 36 * used for forms presented interactively to a user. Forms can also be built and 37 * submitted programmatically without any user input using the 38 * drupal_form_submit() function. 39 * 40 * drupal_get_form() handles retrieving, processing, and displaying a rendered 41 * HTML form for modules automatically. 42 * 43 * Here is an example of how to use drupal_get_form() and a form builder 44 * function: 45 * @code 46 * $form = drupal_get_form('my_module_example_form'); 47 * ... 48 * function my_module_example_form($form, &$form_state) { 49 * $form['submit'] = array( 50 * '#type' => 'submit', 51 * '#value' => t('Submit'), 52 * ); 53 * return $form; 54 * } 55 * function my_module_example_form_validate($form, &$form_state) { 56 * // Validation logic. 57 * } 58 * function my_module_example_form_submit($form, &$form_state) { 59 * // Submission logic. 60 * } 61 * @endcode 62 * 63 * Or with any number of additional arguments: 64 * @code 65 * $extra = "extra"; 66 * $form = drupal_get_form('my_module_example_form', $extra); 67 * ... 68 * function my_module_example_form($form, &$form_state, $extra) { 69 * $form['submit'] = array( 70 * '#type' => 'submit', 71 * '#value' => $extra, 72 * ); 73 * return $form; 74 * } 75 * @endcode 76 * 77 * The $form argument to form-related functions is a structured array containing 78 * the elements and properties of the form. For information on the array 79 * components and format, and more detailed explanations of the Form API 80 * workflow, see the 81 * @link forms_api_reference.html Form API reference @endlink 82 * and the 83 * @link http://drupal.org/node/37775 Form API documentation section. @endlink 84 * In addition, there is a set of Form API tutorials in 85 * @link form_example_tutorial.inc the Form Example Tutorial @endlink which 86 * provide basics all the way up through multistep forms. 87 * 88 * In the form builder, validation, submission, and other form functions, 89 * $form_state is the primary influence on the processing of the form and is 90 * passed by reference to most functions, so they use it to communicate with 91 * the form system and each other. 92 * 93 * See drupal_build_form() for documentation of $form_state keys. 94 */ 95 96 /** 97 * Returns a renderable form array for a given form ID. 98 * 99 * This function should be used instead of drupal_build_form() when $form_state 100 * is not needed (i.e., when initially rendering the form) and is often 101 * used as a menu callback. 102 * 103 * @param $form_id 104 * The unique string identifying the desired form. If a function with that 105 * name exists, it is called to build the form array. Modules that need to 106 * generate the same form (or very similar forms) using different $form_ids 107 * can implement hook_forms(), which maps different $form_id values to the 108 * proper form constructor function. Examples may be found in node_forms(), 109 * and search_forms(). 110 * @param ... 111 * Any additional arguments are passed on to the functions called by 112 * drupal_get_form(), including the unique form constructor function. For 113 * example, the node_edit form requires that a node object is passed in here 114 * when it is called. These are available to implementations of 115 * hook_form_alter() and hook_form_FORM_ID_alter() as the array 116 * $form_state['build_info']['args']. 117 * 118 * @return 119 * The form array. 120 * 121 * @see drupal_build_form() 122 */ 123 function drupal_get_form($form_id) { 124 $form_state = array(); 125 126 $args = func_get_args(); 127 // Remove $form_id from the arguments. 128 array_shift($args); 129 $form_state['build_info']['args'] = $args; 130 131 return drupal_build_form($form_id, $form_state); 132 } 133 134 /** 135 * Builds and process a form based on a form id. 136 * 137 * The form may also be retrieved from the cache if the form was built in a 138 * previous page-load. The form is then passed on for processing, validation 139 * and submission if there is proper input. 140 * 141 * @param $form_id 142 * The unique string identifying the desired form. If a function with that 143 * name exists, it is called to build the form array. Modules that need to 144 * generate the same form (or very similar forms) using different $form_ids 145 * can implement hook_forms(), which maps different $form_id values to the 146 * proper form constructor function. Examples may be found in node_forms(), 147 * and search_forms(). 148 * @param $form_state 149 * An array which stores information about the form. This is passed as a 150 * reference so that the caller can use it to examine what in the form changed 151 * when the form submission process is complete. Furthermore, it may be used 152 * to store information related to the processed data in the form, which will 153 * persist across page requests when the 'cache' or 'rebuild' flag is set. 154 * The following parameters may be set in $form_state to affect how the form 155 * is rendered: 156 * - build_info: Internal. An associative array of information stored by Form 157 * API that is necessary to build and rebuild the form from cache when the 158 * original context may no longer be available: 159 * - args: A list of arguments to pass to the form constructor. 160 * - files: An optional array defining include files that need to be loaded 161 * for building the form. Each array entry may be the path to a file or 162 * another array containing values for the parameters 'type', 'module' and 163 * 'name' as needed by module_load_include(). The files listed here are 164 * automatically loaded by form_get_cache(). By default the current menu 165 * router item's 'file' definition is added, if any. Use 166 * form_load_include() to add include files from a form constructor. 167 * - form_id: Identification of the primary form being constructed and 168 * processed. 169 * - base_form_id: Identification for a base form, as declared in a 170 * hook_forms() implementation. 171 * - rebuild_info: Internal. Similar to 'build_info', but pertaining to 172 * drupal_rebuild_form(). 173 * - rebuild: Normally, after the entire form processing is completed and 174 * submit handlers have run, a form is considered to be done and 175 * drupal_redirect_form() will redirect the user to a new page using a GET 176 * request (so a browser refresh does not re-submit the form). However, if 177 * 'rebuild' has been set to TRUE, then a new copy of the form is 178 * immediately built and sent to the browser, instead of a redirect. This is 179 * used for multi-step forms, such as wizards and confirmation forms. 180 * Normally, $form_state['rebuild'] is set by a submit handler, since it is 181 * usually logic within a submit handler that determines whether a form is 182 * done or requires another step. However, a validation handler may already 183 * set $form_state['rebuild'] to cause the form processing to bypass submit 184 * handlers and rebuild the form instead, even if there are no validation 185 * errors. 186 * - redirect: Used to redirect the form on submission. It may either be a 187 * string containing the destination URL, or an array of arguments 188 * compatible with drupal_goto(). See drupal_redirect_form() for complete 189 * information. 190 * - no_redirect: If set to TRUE the form will NOT perform a drupal_goto(), 191 * even if 'redirect' is set. 192 * - method: The HTTP form method to use for finding the input for this form. 193 * May be 'post' or 'get'. Defaults to 'post'. Note that 'get' method 194 * forms do not use form ids so are always considered to be submitted, which 195 * can have unexpected effects. The 'get' method should only be used on 196 * forms that do not change data, as that is exclusively the domain of 197 * 'post.' 198 * - cache: If set to TRUE the original, unprocessed form structure will be 199 * cached, which allows the entire form to be rebuilt from cache. A typical 200 * form workflow involves two page requests; first, a form is built and 201 * rendered for the user to fill in. Then, the user fills the form in and 202 * submits it, triggering a second page request in which the form must be 203 * built and processed. By default, $form and $form_state are built from 204 * scratch during each of these page requests. Often, it is necessary or 205 * desired to persist the $form and $form_state variables from the initial 206 * page request to the one that processes the submission. 'cache' can be set 207 * to TRUE to do this. A prominent example is an Ajax-enabled form, in which 208 * ajax_process_form() enables form caching for all forms that include an 209 * element with the #ajax property. (The Ajax handler has no way to build 210 * the form itself, so must rely on the cached version.) Note that the 211 * persistence of $form and $form_state happens automatically for 212 * (multi-step) forms having the 'rebuild' flag set, regardless of the value 213 * for 'cache'. 214 * - no_cache: If set to TRUE the form will NOT be cached, even if 'cache' is 215 * set. 216 * - values: An associative array of values submitted to the form. The 217 * validation functions and submit functions use this array for nearly all 218 * their decision making. (Note that #tree determines whether the values are 219 * a flat array or an array whose structure parallels the $form array. See 220 * @link forms_api_reference.html Form API reference @endlink for more 221 * information.) These are raw and unvalidated, so should not be used 222 * without a thorough understanding of security implications. In almost all 223 * cases, code should use the data in the 'values' array exclusively. The 224 * most common use of this key is for multi-step forms that need to clear 225 * some of the user input when setting 'rebuild'. The values correspond to 226 * $_POST or $_GET, depending on the 'method' chosen. 227 * - always_process: If TRUE and the method is GET, a form_id is not 228 * necessary. This should only be used on RESTful GET forms that do NOT 229 * write data, as this could lead to security issues. It is useful so that 230 * searches do not need to have a form_id in their query arguments to 231 * trigger the search. 232 * - must_validate: Ordinarily, a form is only validated once, but there are 233 * times when a form is resubmitted internally and should be validated 234 * again. Setting this to TRUE will force that to happen. This is most 235 * likely to occur during Ajax operations. 236 * - programmed: If TRUE, the form was submitted programmatically, usually 237 * invoked via drupal_form_submit(). Defaults to FALSE. 238 * - process_input: Boolean flag. TRUE signifies correct form submission. 239 * This is always TRUE for programmed forms coming from drupal_form_submit() 240 * (see 'programmed' key), or if the form_id coming from the $_POST data is 241 * set and matches the current form_id. 242 * - submitted: If TRUE, the form has been submitted. Defaults to FALSE. 243 * - executed: If TRUE, the form was submitted and has been processed and 244 * executed. Defaults to FALSE. 245 * - triggering_element: (read-only) The form element that triggered 246 * submission. This is the same as the deprecated 247 * $form_state['clicked_button']. It is the element that caused submission, 248 * which may or may not be a button (in the case of Ajax forms). This key is 249 * often used to distinguish between various buttons in a submit handler, 250 * and is also used in Ajax handlers. 251 * - clicked_button: Deprecated. Use triggering_element instead. 252 * - has_file_element: Internal. If TRUE, there is a file element and Form API 253 * will set the appropriate 'enctype' HTML attribute on the form. 254 * - groups: Internal. An array containing references to fieldsets to render 255 * them within vertical tabs. 256 * - storage: $form_state['storage'] is not a special key, and no specific 257 * support is provided for it in the Form API. By tradition it was 258 * the location where application-specific data was stored for communication 259 * between the submit, validation, and form builder functions, especially 260 * in a multi-step-style form. Form implementations may use any key(s) 261 * within $form_state (other than the keys listed here and other reserved 262 * ones used by Form API internals) for this kind of storage. The 263 * recommended way to ensure that the chosen key doesn't conflict with ones 264 * used by the Form API or other modules is to use the module name as the 265 * key name or a prefix for the key name. For example, the Node module uses 266 * $form_state['node'] in node editing forms to store information about the 267 * node being edited, and this information stays available across successive 268 * clicks of the "Preview" button as well as when the "Save" button is 269 * finally clicked. 270 * - buttons: A list containing copies of all submit and button elements in 271 * the form. 272 * - complete form: A reference to the $form variable containing the complete 273 * form structure. #process, #after_build, #element_validate, and other 274 * handlers being invoked on a form element may use this reference to access 275 * other information in the form the element is contained in. 276 * - temporary: An array holding temporary data accessible during the current 277 * page request only. All $form_state properties that are not reserved keys 278 * (see form_state_keys_no_cache()) persist throughout a multistep form 279 * sequence. Form API provides this key for modules to communicate 280 * information across form-related functions during a single page request. 281 * It may be used to temporarily save data that does not need to or should 282 * not be cached during the whole form workflow; e.g., data that needs to be 283 * accessed during the current form build process only. There is no use-case 284 * for this functionality in Drupal core. 285 * - wrapper_callback: Modules that wish to pre-populate certain forms with 286 * common elements, such as back/next/save buttons in multi-step form 287 * wizards, may define a form builder function name that returns a form 288 * structure, which is passed on to the actual form builder function. 289 * Such implementations may either define the 'wrapper_callback' via 290 * hook_forms() or have to invoke drupal_build_form() (instead of 291 * drupal_get_form()) on their own in a custom menu callback to prepare 292 * $form_state accordingly. 293 * Information on how certain $form_state properties control redirection 294 * behavior after form submission may be found in drupal_redirect_form(). 295 * 296 * @return 297 * The rendered form. This function may also perform a redirect and hence may 298 * not return at all, depending upon the $form_state flags that were set. 299 * 300 * @see drupal_redirect_form() 301 */ 302 function drupal_build_form($form_id, &$form_state) { 303 // Ensure some defaults; if already set they will not be overridden. 304 $form_state += form_state_defaults(); 305 306 if (!isset($form_state['input'])) { 307 $form_state['input'] = $form_state['method'] == 'get' ? $_GET : $_POST; 308 } 309 310 if (isset($_SESSION['batch_form_state'])) { 311 // We've been redirected here after a batch processing. The form has 312 // already been processed, but needs to be rebuilt. See _batch_finished(). 313 $form_state = $_SESSION['batch_form_state']; 314 unset($_SESSION['batch_form_state']); 315 return drupal_rebuild_form($form_id, $form_state); 316 } 317 318 // If the incoming input contains a form_build_id, we'll check the cache for a 319 // copy of the form in question. If it's there, we don't have to rebuild the 320 // form to proceed. In addition, if there is stored form_state data from a 321 // previous step, we'll retrieve it so it can be passed on to the form 322 // processing code. 323 $check_cache = isset($form_state['input']['form_id']) && $form_state['input']['form_id'] == $form_id && !empty($form_state['input']['form_build_id']); 324 if ($check_cache) { 325 $form = form_get_cache($form_state['input']['form_build_id'], $form_state); 326 } 327 328 // If the previous bit of code didn't result in a populated $form object, we 329 // are hitting the form for the first time and we need to build it from 330 // scratch. 331 if (!isset($form)) { 332 // If we attempted to serve the form from cache, uncacheable $form_state 333 // keys need to be removed after retrieving and preparing the form, except 334 // any that were already set prior to retrieving the form. 335 if ($check_cache) { 336 $form_state_before_retrieval = $form_state; 337 } 338 339 $form = drupal_retrieve_form($form_id, $form_state); 340 drupal_prepare_form($form_id, $form, $form_state); 341 342 // form_set_cache() removes uncacheable $form_state keys defined in 343 // form_state_keys_no_cache() in order for multi-step forms to work 344 // properly. This means that form processing logic for single-step forms 345 // using $form_state['cache'] may depend on data stored in those keys 346 // during drupal_retrieve_form()/drupal_prepare_form(), but form 347 // processing should not depend on whether the form is cached or not, so 348 // $form_state is adjusted to match what it would be after a 349 // form_set_cache()/form_get_cache() sequence. These exceptions are 350 // allowed to survive here: 351 // - always_process: Does not make sense in conjunction with form caching 352 // in the first place, since passing form_build_id as a GET parameter is 353 // not desired. 354 // - temporary: Any assigned data is expected to survives within the same 355 // page request. 356 if ($check_cache) { 357 $uncacheable_keys = array_flip(array_diff(form_state_keys_no_cache(), array('always_process', 'temporary'))); 358 $form_state = array_diff_key($form_state, $uncacheable_keys); 359 $form_state += $form_state_before_retrieval; 360 } 361 } 362 363 // Now that we have a constructed form, process it. This is where: 364 // - Element #process functions get called to further refine $form. 365 // - User input, if any, gets incorporated in the #value property of the 366 // corresponding elements and into $form_state['values']. 367 // - Validation and submission handlers are called. 368 // - If this submission is part of a multistep workflow, the form is rebuilt 369 // to contain the information of the next step. 370 // - If necessary, the form and form state are cached or re-cached, so that 371 // appropriate information persists to the next page request. 372 // All of the handlers in the pipeline receive $form_state by reference and 373 // can use it to know or update information about the state of the form. 374 drupal_process_form($form_id, $form, $form_state); 375 376 // If this was a successful submission of a single-step form or the last step 377 // of a multi-step form, then drupal_process_form() issued a redirect to 378 // another page, or back to this page, but as a new request. Therefore, if 379 // we're here, it means that this is either a form being viewed initially 380 // before any user input, or there was a validation error requiring the form 381 // to be re-displayed, or we're in a multi-step workflow and need to display 382 // the form's next step. In any case, we have what we need in $form, and can 383 // return it for rendering. 384 return $form; 385 } 386 387 /** 388 * Retrieves default values for the $form_state array. 389 */ 390 function form_state_defaults() { 391 return array( 392 'rebuild' => FALSE, 393 'rebuild_info' => array(), 394 'redirect' => NULL, 395 // @todo 'args' is usually set, so no other default 'build_info' keys are 396 // appended via += form_state_defaults(). 397 'build_info' => array( 398 'args' => array(), 399 'files' => array(), 400 ), 401 'temporary' => array(), 402 'submitted' => FALSE, 403 'executed' => FALSE, 404 'programmed' => FALSE, 405 'cache'=> FALSE, 406 'method' => 'post', 407 'groups' => array(), 408 'buttons' => array(), 409 ); 410 } 411 412 /** 413 * Constructs a new $form from the information in $form_state. 414 * 415 * This is the key function for making multi-step forms advance from step to 416 * step. It is called by drupal_process_form() when all user input processing, 417 * including calling validation and submission handlers, for the request is 418 * finished. If a validate or submit handler set $form_state['rebuild'] to TRUE, 419 * and if other conditions don't preempt a rebuild from happening, then this 420 * function is called to generate a new $form, the next step in the form 421 * workflow, to be returned for rendering. 422 * 423 * Ajax form submissions are almost always multi-step workflows, so that is one 424 * common use-case during which form rebuilding occurs. See ajax_form_callback() 425 * for more information about creating Ajax-enabled forms. 426 * 427 * @param $form_id 428 * The unique string identifying the desired form. If a function 429 * with that name exists, it is called to build the form array. 430 * Modules that need to generate the same form (or very similar forms) 431 * using different $form_ids can implement hook_forms(), which maps 432 * different $form_id values to the proper form constructor function. Examples 433 * may be found in node_forms() and search_forms(). 434 * @param $form_state 435 * A keyed array containing the current state of the form. 436 * @param $old_form 437 * (optional) A previously built $form. Used to retain the #build_id and 438 * #action properties in Ajax callbacks and similar partial form rebuilds. The 439 * only properties copied from $old_form are the ones which both exist in 440 * $old_form and for which $form_state['rebuild_info']['copy'][PROPERTY] is 441 * TRUE. If $old_form is not passed, the entire $form is rebuilt freshly. 442 * 'rebuild_info' needs to be a separate top-level property next to 443 * 'build_info', since the contained data must not be cached. 444 * 445 * @return 446 * The newly built form. 447 * 448 * @see drupal_process_form() 449 * @see ajax_form_callback() 450 */ 451 function drupal_rebuild_form($form_id, &$form_state, $old_form = NULL) { 452 $form = drupal_retrieve_form($form_id, $form_state); 453 454 // If only parts of the form will be returned to the browser (e.g., Ajax or 455 // RIA clients), re-use the old #build_id to not require client-side code to 456 // manually update the hidden 'build_id' input element. 457 // Otherwise, a new #build_id is generated, to not clobber the previous 458 // build's data in the form cache; also allowing the user to go back to an 459 // earlier build, make changes, and re-submit. 460 // @see drupal_prepare_form() 461 if (isset($old_form['#build_id']) && !empty($form_state['rebuild_info']['copy']['#build_id'])) { 462 $form['#build_id'] = $old_form['#build_id']; 463 } 464 else { 465 $form['#build_id'] = 'form-' . drupal_hash_base64(uniqid(mt_rand(), TRUE) . mt_rand()); 466 } 467 468 // #action defaults to request_uri(), but in case of Ajax and other partial 469 // rebuilds, the form is submitted to an alternate URL, and the original 470 // #action needs to be retained. 471 if (isset($old_form['#action']) && !empty($form_state['rebuild_info']['copy']['#action'])) { 472 $form['#action'] = $old_form['#action']; 473 } 474 475 drupal_prepare_form($form_id, $form, $form_state); 476 477 // Caching is normally done in drupal_process_form(), but what needs to be 478 // cached is the $form structure before it passes through form_builder(), 479 // so we need to do it here. 480 // @todo For Drupal 8, find a way to avoid this code duplication. 481 if (empty($form_state['no_cache'])) { 482 form_set_cache($form['#build_id'], $form, $form_state); 483 } 484 485 // Clear out all group associations as these might be different when 486 // re-rendering the form. 487 $form_state['groups'] = array(); 488 489 // Return a fully built form that is ready for rendering. 490 return form_builder($form_id, $form, $form_state); 491 } 492 493 /** 494 * Fetches a form from cache. 495 */ 496 function form_get_cache($form_build_id, &$form_state) { 497 if ($cached = cache_get('form_' . $form_build_id, 'cache_form')) { 498 $form = $cached->data; 499 500 global $user; 501 if ((isset($form['#cache_token']) && drupal_valid_token($form['#cache_token'])) || (!isset($form['#cache_token']) && !$user->uid)) { 502 if ($cached = cache_get('form_state_' . $form_build_id, 'cache_form')) { 503 // Re-populate $form_state for subsequent rebuilds. 504 $form_state = $cached->data + $form_state; 505 506 // If the original form is contained in include files, load the files. 507 // @see form_load_include() 508 $form_state['build_info'] += array('files' => array()); 509 foreach ($form_state['build_info']['files'] as $file) { 510 if (is_array($file)) { 511 $file += array('type' => 'inc', 'name' => $file['module']); 512 module_load_include($file['type'], $file['module'], $file['name']); 513 } 514 elseif (file_exists($file)) { 515 require_once DRUPAL_ROOT . '/' . $file; 516 } 517 } 518 } 519 return $form; 520 } 521 } 522 } 523 524 /** 525 * Stores a form in the cache. 526 */ 527 function form_set_cache($form_build_id, $form, $form_state) { 528 // 6 hours cache life time for forms should be plenty. 529 $expire = 21600; 530 531 // Cache form structure. 532 if (isset($form)) { 533 if ($GLOBALS['user']->uid) { 534 $form['#cache_token'] = drupal_get_token(); 535 } 536 cache_set('form_' . $form_build_id, $form, 'cache_form', REQUEST_TIME + $expire); 537 } 538 539 // Cache form state. 540 if ($data = array_diff_key($form_state, array_flip(form_state_keys_no_cache()))) { 541 cache_set('form_state_' . $form_build_id, $data, 'cache_form', REQUEST_TIME + $expire); 542 } 543 } 544 545 /** 546 * Returns an array of $form_state keys that shouldn't be cached. 547 */ 548 function form_state_keys_no_cache() { 549 return array( 550 // Public properties defined by form constructors and form handlers. 551 'always_process', 552 'must_validate', 553 'rebuild', 554 'rebuild_info', 555 'redirect', 556 'no_redirect', 557 'temporary', 558 // Internal properties defined by form processing. 559 'buttons', 560 'triggering_element', 561 'clicked_button', 562 'complete form', 563 'groups', 564 'input', 565 'method', 566 'submit_handlers', 567 'submitted', 568 'executed', 569 'validate_handlers', 570 'values', 571 ); 572 } 573 574 /** 575 * Ensures an include file is loaded whenever the form is processed. 576 * 577 * Example: 578 * @code 579 * // Load node.admin.inc from Node module. 580 * form_load_include($form_state, 'inc', 'node', 'node.admin'); 581 * @endcode 582 * 583 * Use this function instead of module_load_include() from inside a form 584 * constructor or any form processing logic as it ensures that the include file 585 * is loaded whenever the form is processed. In contrast to using 586 * module_load_include() directly, form_load_include() makes sure the include 587 * file is correctly loaded also if the form is cached. 588 * 589 * @param $form_state 590 * The current state of the form. 591 * @param $type 592 * The include file's type (file extension). 593 * @param $module 594 * The module to which the include file belongs. 595 * @param $name 596 * (optional) The base file name (without the $type extension). If omitted, 597 * $module is used; i.e., resulting in "$module.$type" by default. 598 * 599 * @return 600 * The filepath of the loaded include file, or FALSE if the include file was 601 * not found or has been loaded already. 602 * 603 * @see module_load_include() 604 */ 605 function form_load_include(&$form_state, $type, $module, $name = NULL) { 606 if (!isset($name)) { 607 $name = $module; 608 } 609 if (!isset($form_state['build_info']['files']["$module:$name.$type"])) { 610 // Only add successfully included files to the form state. 611 if ($result = module_load_include($type, $module, $name)) { 612 $form_state['build_info']['files']["$module:$name.$type"] = array( 613 'type' => $type, 614 'module' => $module, 615 'name' => $name, 616 ); 617 return $result; 618 } 619 } 620 return FALSE; 621 } 622 623 /** 624 * Retrieves, populates, and processes a form. 625 * 626 * This function allows you to supply values for form elements and submit a 627 * form for processing. Compare to drupal_get_form(), which also builds and 628 * processes a form, but does not allow you to supply values. 629 * 630 * There is no return value, but you can check to see if there are errors 631 * by calling form_get_errors(). 632 * 633 * @param $form_id 634 * The unique string identifying the desired form. If a function 635 * with that name exists, it is called to build the form array. 636 * Modules that need to generate the same form (or very similar forms) 637 * using different $form_ids can implement hook_forms(), which maps 638 * different $form_id values to the proper form constructor function. Examples 639 * may be found in node_forms() and search_forms(). 640 * @param $form_state 641 * A keyed array containing the current state of the form. Most important is 642 * the $form_state['values'] collection, a tree of data used to simulate the 643 * incoming $_POST information from a user's form submission. If a key is not 644 * filled in $form_state['values'], then the default value of the respective 645 * element is used. To submit an unchecked checkbox or other control that 646 * browsers submit by not having a $_POST entry, include the key, but set the 647 * value to NULL. 648 * @param ... 649 * Any additional arguments are passed on to the functions called by 650 * drupal_form_submit(), including the unique form constructor function. 651 * For example, the node_edit form requires that a node object be passed 652 * in here when it is called. Arguments that need to be passed by reference 653 * should not be included here, but rather placed directly in the $form_state 654 * build info array so that the reference can be preserved. For example, a 655 * form builder function with the following signature: 656 * @code 657 * function mymodule_form($form, &$form_state, &$object) { 658 * } 659 * @endcode 660 * would be called via drupal_form_submit() as follows: 661 * @code 662 * $form_state['values'] = $my_form_values; 663 * $form_state['build_info']['args'] = array(&$object); 664 * drupal_form_submit('mymodule_form', $form_state); 665 * @endcode 666 * For example: 667 * @code 668 * // register a new user 669 * $form_state = array(); 670 * $form_state['values']['name'] = 'robo-user'; 671 * $form_state['values']['mail'] = 'robouser@example.com'; 672 * $form_state['values']['pass']['pass1'] = 'password'; 673 * $form_state['values']['pass']['pass2'] = 'password'; 674 * $form_state['values']['op'] = t('Create new account'); 675 * drupal_form_submit('user_register_form', $form_state); 676 * @endcode 677 */ 678 function drupal_form_submit($form_id, &$form_state) { 679 if (!isset($form_state['build_info']['args'])) { 680 $args = func_get_args(); 681 array_shift($args); 682 array_shift($args); 683 $form_state['build_info']['args'] = $args; 684 } 685 // Merge in default values. 686 $form_state += form_state_defaults(); 687 688 // Populate $form_state['input'] with the submitted values before retrieving 689 // the form, to be consistent with what drupal_build_form() does for 690 // non-programmatic submissions (form builder functions may expect it to be 691 // there). 692 $form_state['input'] = $form_state['values']; 693 694 $form_state['programmed'] = TRUE; 695 $form = drupal_retrieve_form($form_id, $form_state); 696 // Programmed forms are always submitted. 697 $form_state['submitted'] = TRUE; 698 699 // Reset form validation. 700 $form_state['must_validate'] = TRUE; 701 form_clear_error(); 702 703 drupal_prepare_form($form_id, $form, $form_state); 704 drupal_process_form($form_id, $form, $form_state); 705 } 706 707 /** 708 * Retrieves the structured array that defines a given form. 709 * 710 * @param $form_id 711 * The unique string identifying the desired form. If a function 712 * with that name exists, it is called to build the form array. 713 * Modules that need to generate the same form (or very similar forms) 714 * using different $form_ids can implement hook_forms(), which maps 715 * different $form_id values to the proper form constructor function. 716 * @param $form_state 717 * A keyed array containing the current state of the form, including the 718 * additional arguments to drupal_get_form() or drupal_form_submit() in the 719 * 'args' component of the array. 720 */ 721 function drupal_retrieve_form($form_id, &$form_state) { 722 $forms = &drupal_static(__FUNCTION__); 723 724 // Record the $form_id. 725 $form_state['build_info']['form_id'] = $form_id; 726 727 // Record the filepath of the include file containing the original form, so 728 // the form builder callbacks can be loaded when the form is being rebuilt 729 // from cache on a different path (such as 'system/ajax'). See 730 // form_get_cache(). 731 // $menu_get_item() is not available during installation. 732 if (!isset($form_state['build_info']['files']['menu']) && !defined('MAINTENANCE_MODE')) { 733 $item = menu_get_item(); 734 if (!empty($item['include_file'])) { 735 // Do not use form_load_include() here, as the file is already loaded. 736 // Anyway, form_get_cache() is able to handle filepaths too. 737 $form_state['build_info']['files']['menu'] = $item['include_file']; 738 } 739 } 740 741 // We save two copies of the incoming arguments: one for modules to use 742 // when mapping form ids to constructor functions, and another to pass to 743 // the constructor function itself. 744 $args = $form_state['build_info']['args']; 745 746 // We first check to see if there's a function named after the $form_id. 747 // If there is, we simply pass the arguments on to it to get the form. 748 if (!function_exists($form_id)) { 749 // In cases where many form_ids need to share a central constructor function, 750 // such as the node editing form, modules can implement hook_forms(). It 751 // maps one or more form_ids to the correct constructor functions. 752 // 753 // We cache the results of that hook to save time, but that only works 754 // for modules that know all their form_ids in advance. (A module that 755 // adds a small 'rate this comment' form to each comment in a list 756 // would need a unique form_id for each one, for example.) 757 // 758 // So, we call the hook if $forms isn't yet populated, OR if it doesn't 759 // yet have an entry for the requested form_id. 760 if (!isset($forms) || !isset($forms[$form_id])) { 761 $forms = module_invoke_all('forms', $form_id, $args); 762 } 763 $form_definition = $forms[$form_id]; 764 if (isset($form_definition['callback arguments'])) { 765 $args = array_merge($form_definition['callback arguments'], $args); 766 } 767 if (isset($form_definition['callback'])) { 768 $callback = $form_definition['callback']; 769 $form_state['build_info']['base_form_id'] = $callback; 770 } 771 // In case $form_state['wrapper_callback'] is not defined already, we also 772 // allow hook_forms() to define one. 773 if (!isset($form_state['wrapper_callback']) && isset($form_definition['wrapper_callback'])) { 774 $form_state['wrapper_callback'] = $form_definition['wrapper_callback']; 775 } 776 } 777 778 $form = array(); 779 // We need to pass $form_state by reference in order for forms to modify it, 780 // since call_user_func_array() requires that referenced variables are passed 781 // explicitly. 782 $args = array_merge(array($form, &$form_state), $args); 783 784 // When the passed $form_state (not using drupal_get_form()) defines a 785 // 'wrapper_callback', then it requests to invoke a separate (wrapping) form 786 // builder function to pre-populate the $form array with form elements, which 787 // the actual form builder function ($callback) expects. This allows for 788 // pre-populating a form with common elements for certain forms, such as 789 // back/next/save buttons in multi-step form wizards. See drupal_build_form(). 790 if (isset($form_state['wrapper_callback']) && function_exists($form_state['wrapper_callback'])) { 791 $form = call_user_func_array($form_state['wrapper_callback'], $args); 792 // Put the prepopulated $form into $args. 793 $args[0] = $form; 794 } 795 796 // If $callback was returned by a hook_forms() implementation, call it. 797 // Otherwise, call the function named after the form id. 798 $form = call_user_func_array(isset($callback) ? $callback : $form_id, $args); 799 $form['#form_id'] = $form_id; 800 801 return $form; 802 } 803 804 /** 805 * Processes a form submission. 806 * 807 * This function is the heart of form API. The form gets built, validated and in 808 * appropriate cases, submitted and rebuilt. 809 * 810 * @param $form_id 811 * The unique string identifying the current form. 812 * @param $form 813 * An associative array containing the structure of the form. 814 * @param $form_state 815 * A keyed array containing the current state of the form. This 816 * includes the current persistent storage data for the form, and 817 * any data passed along by earlier steps when displaying a 818 * multi-step form. Additional information, like the sanitized $_POST 819 * data, is also accumulated here. 820 */ 821 function drupal_process_form($form_id, &$form, &$form_state) { 822 $form_state['values'] = array(); 823 824 // With $_GET, these forms are always submitted if requested. 825 if ($form_state['method'] == 'get' && !empty($form_state['always_process'])) { 826 if (!isset($form_state['input']['form_build_id'])) { 827 $form_state['input']['form_build_id'] = $form['#build_id']; 828 } 829 if (!isset($form_state['input']['form_id'])) { 830 $form_state['input']['form_id'] = $form_id; 831 } 832 if (!isset($form_state['input']['form_token']) && isset($form['#token'])) { 833 $form_state['input']['form_token'] = drupal_get_token($form['#token']); 834 } 835 } 836 837 // form_builder() finishes building the form by calling element #process 838 // functions and mapping user input, if any, to #value properties, and also 839 // storing the values in $form_state['values']. We need to retain the 840 // unprocessed $form in case it needs to be cached. 841 $unprocessed_form = $form; 842 $form = form_builder($form_id, $form, $form_state); 843 844 // Only process the input if we have a correct form submission. 845 if ($form_state['process_input']) { 846 drupal_validate_form($form_id, $form, $form_state); 847 848 // drupal_html_id() maintains a cache of element IDs it has seen, 849 // so it can prevent duplicates. We want to be sure we reset that 850 // cache when a form is processed, so scenarios that result in 851 // the form being built behind the scenes and again for the 852 // browser don't increment all the element IDs needlessly. 853 if (!form_get_errors()) { 854 // In case of errors, do not break HTML IDs of other forms. 855 drupal_static_reset('drupal_html_id'); 856 } 857 858 if ($form_state['submitted'] && !form_get_errors() && !$form_state['rebuild']) { 859 // Execute form submit handlers. 860 form_execute_handlers('submit', $form, $form_state); 861 862 // We'll clear out the cached copies of the form and its stored data 863 // here, as we've finished with them. The in-memory copies are still 864 // here, though. 865 if (!variable_get('cache', 0) && !empty($form_state['values']['form_build_id'])) { 866 cache_clear_all('form_' . $form_state['values']['form_build_id'], 'cache_form'); 867 cache_clear_all('form_state_' . $form_state['values']['form_build_id'], 'cache_form'); 868 } 869 870 // If batches were set in the submit handlers, we process them now, 871 // possibly ending execution. We make sure we do not react to the batch 872 // that is already being processed (if a batch operation performs a 873 // drupal_form_submit). 874 if ($batch =& batch_get() && !isset($batch['current_set'])) { 875 // Store $form_state information in the batch definition. 876 // We need the full $form_state when either: 877 // - Some submit handlers were saved to be called during batch 878 // processing. See form_execute_handlers(). 879 // - The form is multistep. 880 // In other cases, we only need the information expected by 881 // drupal_redirect_form(). 882 if ($batch['has_form_submits'] || !empty($form_state['rebuild'])) { 883 $batch['form_state'] = $form_state; 884 } 885 else { 886 $batch['form_state'] = array_intersect_key($form_state, array_flip(array('programmed', 'rebuild', 'storage', 'no_redirect', 'redirect'))); 887 } 888 889 $batch['progressive'] = !$form_state['programmed']; 890 batch_process(); 891 892 // Execution continues only for programmatic forms. 893 // For 'regular' forms, we get redirected to the batch processing 894 // page. Form redirection will be handled in _batch_finished(), 895 // after the batch is processed. 896 } 897 898 // Set a flag to indicate the the form has been processed and executed. 899 $form_state['executed'] = TRUE; 900 901 // Redirect the form based on values in $form_state. 902 drupal_redirect_form($form_state); 903 } 904 905 // Don't rebuild or cache form submissions invoked via drupal_form_submit(). 906 if (!empty($form_state['programmed'])) { 907 return; 908 } 909 910 // If $form_state['rebuild'] has been set and input has been processed 911 // without validation errors, we are in a multi-step workflow that is not 912 // yet complete. A new $form needs to be constructed based on the changes 913 // made to $form_state during this request. Normally, a submit handler sets 914 // $form_state['rebuild'] if a fully executed form requires another step. 915 // However, for forms that have not been fully executed (e.g., Ajax 916 // submissions triggered by non-buttons), there is no submit handler to set 917 // $form_state['rebuild']. It would not make sense to redisplay the 918 // identical form without an error for the user to correct, so we also 919 // rebuild error-free non-executed forms, regardless of 920 // $form_state['rebuild']. 921 // @todo D8: Simplify this logic; considering Ajax and non-HTML front-ends, 922 // along with element-level #submit properties, it makes no sense to have 923 // divergent form execution based on whether the triggering element has 924 // #executes_submit_callback set to TRUE. 925 if (($form_state['rebuild'] || !$form_state['executed']) && !form_get_errors()) { 926 // Form building functions (e.g., _form_builder_handle_input_element()) 927 // may use $form_state['rebuild'] to determine if they are running in the 928 // context of a rebuild, so ensure it is set. 929 $form_state['rebuild'] = TRUE; 930 $form = drupal_rebuild_form($form_id, $form_state, $form); 931 } 932 } 933 934 // After processing the form, the form builder or a #process callback may 935 // have set $form_state['cache'] to indicate that the form and form state 936 // shall be cached. But the form may only be cached if the 'no_cache' property 937 // is not set to TRUE. Only cache $form as it was prior to form_builder(), 938 // because form_builder() must run for each request to accommodate new user 939 // input. Rebuilt forms are not cached here, because drupal_rebuild_form() 940 // already takes care of that. 941 if (!$form_state['rebuild'] && $form_state['cache'] && empty($form_state['no_cache'])) { 942 form_set_cache($form['#build_id'], $unprocessed_form, $form_state); 943 } 944 } 945 946 /** 947 * Prepares a structured form array. 948 * 949 * Adds required elements, executes any hook_form_alter functions, and 950 * optionally inserts a validation token to prevent tampering. 951 * 952 * @param $form_id 953 * A unique string identifying the form for validation, submission, 954 * theming, and hook_form_alter functions. 955 * @param $form 956 * An associative array containing the structure of the form. 957 * @param $form_state 958 * A keyed array containing the current state of the form. Passed 959 * in here so that hook_form_alter() calls can use it, as well. 960 */ 961 function drupal_prepare_form($form_id, &$form, &$form_state) { 962 global $user; 963 964 $form['#type'] = 'form'; 965 $form_state['programmed'] = isset($form_state['programmed']) ? $form_state['programmed'] : FALSE; 966 967 // Fix the form method, if it is 'get' in $form_state, but not in $form. 968 if ($form_state['method'] == 'get' && !isset($form['#method'])) { 969 $form['#method'] = 'get'; 970 } 971 972 // Generate a new #build_id for this form, if none has been set already. The 973 // form_build_id is used as key to cache a particular build of the form. For 974 // multi-step forms, this allows the user to go back to an earlier build, make 975 // changes, and re-submit. 976 // @see drupal_build_form() 977 // @see drupal_rebuild_form() 978 if (!isset($form['#build_id'])) { 979 $form['#build_id'] = 'form-' . drupal_hash_base64(uniqid(mt_rand(), TRUE) . mt_rand()); 980 } 981 $form['form_build_id'] = array( 982 '#type' => 'hidden', 983 '#value' => $form['#build_id'], 984 '#id' => $form['#build_id'], 985 '#name' => 'form_build_id', 986 // Form processing and validation requires this value, so ensure the 987 // submitted form value appears literally, regardless of custom #tree 988 // and #parents being set elsewhere. 989 '#parents' => array('form_build_id'), 990 ); 991 992 // Add a token, based on either #token or form_id, to any form displayed to 993 // authenticated users. This ensures that any submitted form was actually 994 // requested previously by the user and protects against cross site request 995 // forgeries. 996 // This does not apply to programmatically submitted forms. Furthermore, since 997 // tokens are session-bound and forms displayed to anonymous users are very 998 // likely cached, we cannot assign a token for them. 999 // During installation, there is no $user yet. 1000 if (!empty($user->uid) && !$form_state['programmed']) { 1001 // Form constructors may explicitly set #token to FALSE when cross site 1002 // request forgery is irrelevant to the form, such as search forms. 1003 if (isset($form['#token']) && $form['#token'] === FALSE) { 1004 unset($form['#token']); 1005 } 1006 // Otherwise, generate a public token based on the form id. 1007 else { 1008 $form['#token'] = $form_id; 1009 $form['form_token'] = array( 1010 '#id' => drupal_html_id('edit-' . $form_id . '-form-token'), 1011 '#type' => 'token', 1012 '#default_value' => drupal_get_token($form['#token']), 1013 // Form processing and validation requires this value, so ensure the 1014 // submitted form value appears literally, regardless of custom #tree 1015 // and #parents being set elsewhere. 1016 '#parents' => array('form_token'), 1017 ); 1018 } 1019 } 1020 1021 if (isset($form_id)) { 1022 $form['form_id'] = array( 1023 '#type' => 'hidden', 1024 '#value' => $form_id, 1025 '#id' => drupal_html_id("edit-$form_id"), 1026 // Form processing and validation requires this value, so ensure the 1027 // submitted form value appears literally, regardless of custom #tree 1028 // and #parents being set elsewhere. 1029 '#parents' => array('form_id'), 1030 ); 1031 } 1032 if (!isset($form['#id'])) { 1033 $form['#id'] = drupal_html_id($form_id); 1034 } 1035 1036 $form += element_info('form'); 1037 $form += array('#tree' => FALSE, '#parents' => array()); 1038 1039 if (!isset($form['#validate'])) { 1040 // Ensure that modules can rely on #validate being set. 1041 $form['#validate'] = array(); 1042 // Check for a handler specific to $form_id. 1043 if (function_exists($form_id . '_validate')) { 1044 $form['#validate'][] = $form_id . '_validate'; 1045 } 1046 // Otherwise check whether this is a shared form and whether there is a 1047 // handler for the shared $form_id. 1048 elseif (isset($form_state['build_info']['base_form_id']) && function_exists($form_state['build_info']['base_form_id'] . '_validate')) { 1049 $form['#validate'][] = $form_state['build_info']['base_form_id'] . '_validate'; 1050 } 1051 } 1052 1053 if (!isset($form['#submit'])) { 1054 // Ensure that modules can rely on #submit being set. 1055 $form['#submit'] = array(); 1056 // Check for a handler specific to $form_id. 1057 if (function_exists($form_id . '_submit')) { 1058 $form['#submit'][] = $form_id . '_submit'; 1059 } 1060 // Otherwise check whether this is a shared form and whether there is a 1061 // handler for the shared $form_id. 1062 elseif (isset($form_state['build_info']['base_form_id']) && function_exists($form_state['build_info']['base_form_id'] . '_submit')) { 1063 $form['#submit'][] = $form_state['build_info']['base_form_id'] . '_submit'; 1064 } 1065 } 1066 1067 // If no #theme has been set, automatically apply theme suggestions. 1068 // theme_form() itself is in #theme_wrappers and not #theme. Therefore, the 1069 // #theme function only has to care for rendering the inner form elements, 1070 // not the form itself. 1071 if (!isset($form['#theme'])) { 1072 $form['#theme'] = array($form_id); 1073 if (isset($form_state['build_info']['base_form_id'])) { 1074 $form['#theme'][] = $form_state['build_info']['base_form_id']; 1075 } 1076 } 1077 1078 // Invoke hook_form_alter(), hook_form_BASE_FORM_ID_alter(), and 1079 // hook_form_FORM_ID_alter() implementations. 1080 $hooks = array('form'); 1081 if (isset($form_state['build_info']['base_form_id'])) { 1082 $hooks[] = 'form_' . $form_state['build_info']['base_form_id']; 1083 } 1084 $hooks[] = 'form_' . $form_id; 1085 drupal_alter($hooks, $form, $form_state, $form_id); 1086 } 1087 1088 1089 /** 1090 * Validates user-submitted form data in the $form_state array. 1091 * 1092 * @param $form_id 1093 * A unique string identifying the form for validation, submission, 1094 * theming, and hook_form_alter functions. 1095 * @param $form 1096 * An associative array containing the structure of the form, which is passed 1097 * by reference. Form validation handlers are able to alter the form structure 1098 * (like #process and #after_build callbacks during form building) in case of 1099 * a validation error. If a validation handler alters the form structure, it 1100 * is responsible for validating the values of changed form elements in 1101 * $form_state['values'] to prevent form submit handlers from receiving 1102 * unvalidated values. 1103 * @param $form_state 1104 * A keyed array containing the current state of the form. The current 1105 * user-submitted data is stored in $form_state['values'], though 1106 * form validation functions are passed an explicit copy of the 1107 * values for the sake of simplicity. Validation handlers can also use 1108 * $form_state to pass information on to submit handlers. For example: 1109 * $form_state['data_for_submission'] = $data; 1110 * This technique is useful when validation requires file parsing, 1111 * web service requests, or other expensive requests that should 1112 * not be repeated in the submission step. 1113 */ 1114 function drupal_validate_form($form_id, &$form, &$form_state) { 1115 $validated_forms = &drupal_static(__FUNCTION__, array()); 1116 1117 if (isset($validated_forms[$form_id]) && empty($form_state['must_validate'])) { 1118 return; 1119 } 1120 1121 // If the session token was set by drupal_prepare_form(), ensure that it 1122 // matches the current user's session. 1123 if (isset($form['#token'])) { 1124 if (!drupal_valid_token($form_state['values']['form_token'], $form['#token'])) { 1125 $path = current_path(); 1126 $query = drupal_get_query_parameters(); 1127 $url = url($path, array('query' => $query)); 1128 1129 // Setting this error will cause the form to fail validation. 1130 form_set_error('form_token', t('The form has become outdated. Copy any unsaved work in the form below and then <a href="@link">reload this page</a>.', array('@link' => $url))); 1131 } 1132 } 1133 1134 _form_validate($form, $form_state, $form_id); 1135 $validated_forms[$form_id] = TRUE; 1136 1137 // If validation errors are limited then remove any non validated form values, 1138 // so that only values that passed validation are left for submit callbacks. 1139 if (isset($form_state['triggering_element']['#limit_validation_errors']) && $form_state['triggering_element']['#limit_validation_errors'] !== FALSE) { 1140 $values = array(); 1141 foreach ($form_state['triggering_element']['#limit_validation_errors'] as $section) { 1142 // If the section exists within $form_state['values'], even if the value 1143 // is NULL, copy it to $values. 1144 $section_exists = NULL; 1145 $value = drupal_array_get_nested_value($form_state['values'], $section, $section_exists); 1146 if ($section_exists) { 1147 drupal_array_set_nested_value($values, $section, $value); 1148 } 1149 } 1150 // A button's #value does not require validation, so for convenience we 1151 // allow the value of the clicked button to be retained in its normal 1152 // $form_state['values'] locations, even if these locations are not included 1153 // in #limit_validation_errors. 1154 if (isset($form_state['triggering_element']['#button_type'])) { 1155 $button_value = $form_state['triggering_element']['#value']; 1156 1157 // Like all input controls, the button value may be in the location 1158 // dictated by #parents. If it is, copy it to $values, but do not override 1159 // what may already be in $values. 1160 $parents = $form_state['triggering_element']['#parents']; 1161 if (!drupal_array_nested_key_exists($values, $parents) && drupal_array_get_nested_value($form_state['values'], $parents) === $button_value) { 1162 drupal_array_set_nested_value($values, $parents, $button_value); 1163 } 1164 1165 // Additionally, form_builder() places the button value in 1166 // $form_state['values'][BUTTON_NAME]. If it's still there, after 1167 // validation handlers have run, copy it to $values, but do not override 1168 // what may already be in $values. 1169 $name = $form_state['triggering_element']['#name']; 1170 if (!isset($values[$name]) && isset($form_state['values'][$name]) && $form_state['values'][$name] === $button_value) { 1171 $values[$name] = $button_value; 1172 } 1173 } 1174 $form_state['values'] = $values; 1175 } 1176 } 1177 1178 /** 1179 * Redirects the user to a URL after a form has been processed. 1180 * 1181 * After a form is submitted and processed, normally the user should be 1182 * redirected to a new destination page. This function figures out what that 1183 * destination should be, based on the $form_state array and the 'destination' 1184 * query string in the request URL, and redirects the user there. 1185 * 1186 * Usually (for exceptions, see below) $form_state['redirect'] determines where 1187 * to redirect the user. This can be set either to a string (the path to 1188 * redirect to), or an array of arguments for drupal_goto(). If 1189 * $form_state['redirect'] is missing, the user is usually (again, see below for 1190 * exceptions) redirected back to the page they came from, where they should see 1191 * a fresh, unpopulated copy of the form. 1192 * 1193 * Here is an example of how to set up a form to redirect to the path 'node': 1194 * @code 1195 * $form_state['redirect'] = 'node'; 1196 * @endcode 1197 * And here is an example of how to redirect to 'node/123?foo=bar#baz': 1198 * @code 1199 * $form_state['redirect'] = array( 1200 * 'node/123', 1201 * array( 1202 * 'query' => array( 1203 * 'foo' => 'bar', 1204 * ), 1205 * 'fragment' => 'baz', 1206 * ), 1207 * ); 1208 * @endcode 1209 * 1210 * There are several exceptions to the "usual" behavior described above: 1211 * - If $form_state['programmed'] is TRUE, the form submission was usually 1212 * invoked via drupal_form_submit(), so any redirection would break the script 1213 * that invoked drupal_form_submit() and no redirection is done. 1214 * - If $form_state['rebuild'] is TRUE, the form is being rebuilt, and no 1215 * redirection is done. 1216 * - If $form_state['no_redirect'] is TRUE, redirection is disabled. This is 1217 * set, for instance, by ajax_get_form() to prevent redirection in Ajax 1218 * callbacks. $form_state['no_redirect'] should never be set or altered by 1219 * form builder functions or form validation/submit handlers. 1220 * - If $form_state['redirect'] is set to FALSE, redirection is disabled. 1221 * - If none of the above conditions has prevented redirection, then the 1222 * redirect is accomplished by calling drupal_goto(), passing in the value of 1223 * $form_state['redirect'] if it is set, or the current path if it is 1224 * not. drupal_goto() preferentially uses the value of $_GET['destination'] 1225 * (the 'destination' URL query string) if it is present, so this will 1226 * override any values set by $form_state['redirect']. Note that during 1227 * installation, install_goto() is called in place of drupal_goto(). 1228 * 1229 * @param $form_state 1230 * An associative array containing the current state of the form. 1231 * 1232 * @see drupal_process_form() 1233 * @see drupal_build_form() 1234 */ 1235 function drupal_redirect_form($form_state) { 1236 // Skip redirection for form submissions invoked via drupal_form_submit(). 1237 if (!empty($form_state['programmed'])) { 1238 return; 1239 } 1240 // Skip redirection if rebuild is activated. 1241 if (!empty($form_state['rebuild'])) { 1242 return; 1243 } 1244 // Skip redirection if it was explicitly disallowed. 1245 if (!empty($form_state['no_redirect'])) { 1246 return; 1247 } 1248 // Only invoke drupal_goto() if redirect value was not set to FALSE. 1249 if (!isset($form_state['redirect']) || $form_state['redirect'] !== FALSE) { 1250 if (isset($form_state['redirect'])) { 1251 if (is_array($form_state['redirect'])) { 1252 call_user_func_array('drupal_goto', $form_state['redirect']); 1253 } 1254 else { 1255 // This function can be called from the installer, which guarantees 1256 // that $redirect will always be a string, so catch that case here 1257 // and use the appropriate redirect function. 1258 $function = drupal_installation_attempted() ? 'install_goto' : 'drupal_goto'; 1259 $function($form_state['redirect']); 1260 } 1261 } 1262 drupal_goto(current_path(), array('query' => drupal_get_query_parameters())); 1263 } 1264 } 1265 1266 /** 1267 * Performs validation on form elements. 1268 * 1269 * First ensures required fields are completed, #maxlength is not exceeded, and 1270 * selected options were in the list of options given to the user. Then calls 1271 * user-defined validators. 1272 * 1273 * @param $elements 1274 * An associative array containing the structure of the form. 1275 * @param $form_state 1276 * A keyed array containing the current state of the form. The current 1277 * user-submitted data is stored in $form_state['values'], though 1278 * form validation functions are passed an explicit copy of the 1279 * values for the sake of simplicity. Validation handlers can also 1280 * $form_state to pass information on to submit handlers. For example: 1281 * $form_state['data_for_submission'] = $data; 1282 * This technique is useful when validation requires file parsing, 1283 * web service requests, or other expensive requests that should 1284 * not be repeated in the submission step. 1285 * @param $form_id 1286 * A unique string identifying the form for validation, submission, 1287 * theming, and hook_form_alter functions. 1288 */ 1289 function _form_validate(&$elements, &$form_state, $form_id = NULL) { 1290 // Also used in the installer, pre-database setup. 1291 $t = get_t(); 1292 1293 // Recurse through all children. 1294 foreach (element_children($elements) as $key) { 1295 if (isset($elements[$key]) && $elements[$key]) { 1296 _form_validate($elements[$key], $form_state); 1297 } 1298 } 1299 1300 // Validate the current input. 1301 if (!isset($elements['#validated']) || !$elements['#validated']) { 1302 // The following errors are always shown. 1303 if (isset($elements['#needs_validation'])) { 1304 // Verify that the value is not longer than #maxlength. 1305 if (isset($elements['#maxlength']) && drupal_strlen($elements['#value']) > $elements['#maxlength']) { 1306 form_error($elements, $t('!name cannot be longer than %max characters but is currently %length characters long.', array('!name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title'], '%max' => $elements['#maxlength'], '%length' => drupal_strlen($elements['#value'])))); 1307 } 1308 1309 if (isset($elements['#options']) && isset($elements['#value'])) { 1310 if ($elements['#type'] == 'select') { 1311 $options = form_options_flatten($elements['#options']); 1312 } 1313 else { 1314 $options = $elements['#options']; 1315 } 1316 if (is_array($elements['#value'])) { 1317 $value = in_array($elements['#type'], array('checkboxes', 'tableselect')) ? array_keys($elements['#value']) : $elements['#value']; 1318 foreach ($value as $v) { 1319 if (!isset($options[$v])) { 1320 form_error($elements, $t('An illegal choice has been detected. Please contact the site administrator.')); 1321 watchdog('form', 'Illegal choice %choice in !name element.', array('%choice' => $v, '!name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title']), WATCHDOG_ERROR); 1322 } 1323 } 1324 } 1325 // Non-multiple select fields always have a value in HTML. If the user 1326 // does not change the form, it will be the value of the first option. 1327 // Because of this, form validation for the field will almost always 1328 // pass, even if the user did not select anything. To work around this 1329 // browser behavior, required select fields without a #default_value get 1330 // an additional, first empty option. In case the submitted value is 1331 // identical to the empty option's value, we reset the element's value 1332 // to NULL to trigger the regular #required handling below. 1333 // @see form_process_select() 1334 elseif ($elements['#type'] == 'select' && !$elements['#multiple'] && $elements['#required'] && !isset($elements['#default_value']) && $elements['#value'] === $elements['#empty_value']) { 1335 $elements['#value'] = NULL; 1336 form_set_value($elements, NULL, $form_state); 1337 } 1338 elseif (!isset($options[$elements['#value']])) { 1339 form_error($elements, $t('An illegal choice has been detected. Please contact the site administrator.')); 1340 watchdog('form', 'Illegal choice %choice in %name element.', array('%choice' => $elements['#value'], '%name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title']), WATCHDOG_ERROR); 1341 } 1342 } 1343 } 1344 1345 // While this element is being validated, it may be desired that some calls 1346 // to form_set_error() be suppressed and not result in a form error, so 1347 // that a button that implements low-risk functionality (such as "Previous" 1348 // or "Add more") that doesn't require all user input to be valid can still 1349 // have its submit handlers triggered. The triggering element's 1350 // #limit_validation_errors property contains the information for which 1351 // errors are needed, and all other errors are to be suppressed. The 1352 // #limit_validation_errors property is ignored if submit handlers will run, 1353 // but the element doesn't have a #submit property, because it's too large a 1354 // security risk to have any invalid user input when executing form-level 1355 // submit handlers. 1356 if (isset($form_state['triggering_element']['#limit_validation_errors']) && ($form_state['triggering_element']['#limit_validation_errors'] !== FALSE) && !($form_state['submitted'] && !isset($form_state['triggering_element']['#submit']))) { 1357 form_set_error(NULL, '', $form_state['triggering_element']['#limit_validation_errors']); 1358 } 1359 // If submit handlers won't run (due to the submission having been triggered 1360 // by an element whose #executes_submit_callback property isn't TRUE), then 1361 // it's safe to suppress all validation errors, and we do so by default, 1362 // which is particularly useful during an Ajax submission triggered by a 1363 // non-button. An element can override this default by setting the 1364 // #limit_validation_errors property. For button element types, 1365 // #limit_validation_errors defaults to FALSE (via system_element_info()), 1366 // so that full validation is their default behavior. 1367 elseif (isset($form_state['triggering_element']) && !isset($form_state['triggering_element']['#limit_validation_errors']) && !$form_state['submitted']) { 1368 form_set_error(NULL, '', array()); 1369 } 1370 // As an extra security measure, explicitly turn off error suppression if 1371 // one of the above conditions wasn't met. Since this is also done at the 1372 // end of this function, doing it here is only to handle the rare edge case 1373 // where a validate handler invokes form processing of another form. 1374 else { 1375 drupal_static_reset('form_set_error:limit_validation_errors'); 1376 } 1377 1378 // Make sure a value is passed when the field is required. 1379 if (isset($elements['#needs_validation']) && $elements['#required']) { 1380 // A simple call to empty() will not cut it here as some fields, like 1381 // checkboxes, can return a valid value of '0'. Instead, check the 1382 // length if it's a string, and the item count if it's an array. 1383 // An unchecked checkbox has a #value of integer 0, different than string 1384 // '0', which could be a valid value. 1385 $is_empty_multiple = (!count($elements['#value'])); 1386 $is_empty_string = (is_string($elements['#value']) && drupal_strlen(trim($elements['#value'])) == 0); 1387 $is_empty_value = ($elements['#value'] === 0); 1388 if ($is_empty_multiple || $is_empty_string || $is_empty_value) { 1389 // Although discouraged, a #title is not mandatory for form elements. In 1390 // case there is no #title, we cannot set a form error message. 1391 // Instead of setting no #title, form constructors are encouraged to set 1392 // #title_display to 'invisible' to improve accessibility. 1393 if (isset($elements['#title'])) { 1394 form_error($elements, $t('!name field is required.', array('!name' => $elements['#title']))); 1395 } 1396 else { 1397 form_error($elements); 1398 } 1399 } 1400 } 1401 1402 // Call user-defined form level validators. 1403 if (isset($form_id)) { 1404 form_execute_handlers('validate', $elements, $form_state); 1405 } 1406 // Call any element-specific validators. These must act on the element 1407 // #value data. 1408 elseif (isset($elements['#element_validate'])) { 1409 foreach ($elements['#element_validate'] as $function) { 1410 $function($elements, $form_state, $form_state['complete form']); 1411 } 1412 } 1413 $elements['#validated'] = TRUE; 1414 } 1415 1416 // Done validating this element, so turn off error suppression. 1417 // _form_validate() turns it on again when starting on the next element, if 1418 // it's still appropriate to do so. 1419 drupal_static_reset('form_set_error:limit_validation_errors'); 1420 } 1421 1422 /** 1423 * Executes custom validation and submission handlers for a given form. 1424 * 1425 * Button-specific handlers are checked first. If none exist, the function 1426 * falls back to form-level handlers. 1427 * 1428 * @param $type 1429 * The type of handler to execute. 'validate' or 'submit' are the 1430 * defaults used by Form API. 1431 * @param $form 1432 * An associative array containing the structure of the form. 1433 * @param $form_state 1434 * A keyed array containing the current state of the form. If the user 1435 * submitted the form by clicking a button with custom handler functions 1436 * defined, those handlers will be stored here. 1437 */ 1438 function form_execute_handlers($type, &$form, &$form_state) { 1439 $return = FALSE; 1440 // If there was a button pressed, use its handlers. 1441 if (isset($form_state[$type . '_handlers'])) { 1442 $handlers = $form_state[$type . '_handlers']; 1443 } 1444 // Otherwise, check for a form-level handler. 1445 elseif (isset($form['#' . $type])) { 1446 $handlers = $form['#' . $type]; 1447 } 1448 else { 1449 $handlers = array(); 1450 } 1451 1452 foreach ($handlers as $function) { 1453 // Check if a previous _submit handler has set a batch, but make sure we 1454 // do not react to a batch that is already being processed (for instance 1455 // if a batch operation performs a drupal_form_submit()). 1456 if ($type == 'submit' && ($batch =& batch_get()) && !isset($batch['id'])) { 1457 // Some previous submit handler has set a batch. To ensure correct 1458 // execution order, store the call in a special 'control' batch set. 1459 // See _batch_next_set(). 1460 $batch['sets'][] = array('form_submit' => $function); 1461 $batch['has_form_submits'] = TRUE; 1462 } 1463 else { 1464 $function($form, $form_state); 1465 } 1466 $return = TRUE; 1467 } 1468 return $return; 1469 } 1470 1471 /** 1472 * Files an error against a form element. 1473 * 1474 * When a validation error is detected, the validator calls form_set_error() to 1475 * indicate which element needs to be changed and provide an error message. This 1476 * causes the Form API to not execute the form submit handlers, and instead to 1477 * re-display the form to the user with the corresponding elements rendered with 1478 * an 'error' CSS class (shown as red by default). 1479 * 1480 * The standard form_set_error() behavior can be changed if a button provides 1481 * the #limit_validation_errors property. Multistep forms not wanting to 1482 * validate the whole form can set #limit_validation_errors on buttons to 1483 * limit validation errors to only certain elements. For example, pressing the 1484 * "Previous" button in a multistep form should not fire validation errors just 1485 * because the current step has invalid values. If #limit_validation_errors is 1486 * set on a clicked button, the button must also define a #submit property 1487 * (may be set to an empty array). Any #submit handlers will be executed even if 1488 * there is invalid input, so extreme care should be taken with respect to any 1489 * actions taken by them. This is typically not a problem with buttons like 1490 * "Previous" or "Add more" that do not invoke persistent storage of the 1491 * submitted form values. Do not use the #limit_validation_errors property on 1492 * buttons that trigger saving of form values to the database. 1493 * 1494 * The #limit_validation_errors property is a list of "sections" within 1495 * $form_state['values'] that must contain valid values. Each "section" is an 1496 * array with the ordered set of keys needed to reach that part of 1497 * $form_state['values'] (i.e., the #parents property of the element). 1498 * 1499 * Example 1: Allow the "Previous" button to function, regardless of whether any 1500 * user input is valid. 1501 * 1502 * @code 1503 * $form['actions']['previous'] = array( 1504 * '#type' => 'submit', 1505 * '#value' => t('Previous'), 1506 * '#limit_validation_errors' => array(), // No validation. 1507 * '#submit' => array('some_submit_function'), // #submit required. 1508 * ); 1509 * @endcode 1510 * 1511 * Example 2: Require some, but not all, user input to be valid to process the 1512 * submission of a "Previous" button. 1513 * 1514 * @code 1515 * $form['actions']['previous'] = array( 1516 * '#type' => 'submit', 1517 * '#value' => t('Previous'), 1518 * '#limit_validation_errors' => array( 1519 * array('step1'), // Validate $form_state['values']['step1']. 1520 * array('foo', 'bar'), // Validate $form_state['values']['foo']['bar']. 1521 * ), 1522 * '#submit' => array('some_submit_function'), // #submit required. 1523 * ); 1524 * @endcode 1525 * 1526 * This will require $form_state['values']['step1'] and everything within it 1527 * (for example, $form_state['values']['step1']['choice']) to be valid, so 1528 * calls to form_set_error('step1', $message) or 1529 * form_set_error('step1][choice', $message) will prevent the submit handlers 1530 * from running, and result in the error message being displayed to the user. 1531 * However, calls to form_set_error('step2', $message) and 1532 * form_set_error('step2][groupX][choiceY', $message) will be suppressed, 1533 * resulting in the message not being displayed to the user, and the submit 1534 * handlers will run despite $form_state['values']['step2'] and 1535 * $form_state['values']['step2']['groupX']['choiceY'] containing invalid 1536 * values. Errors for an invalid $form_state['values']['foo'] will be 1537 * suppressed, but errors flagging invalid values for 1538 * $form_state['values']['foo']['bar'] and everything within it will be 1539 * flagged and submission prevented. 1540 * 1541 * Partial form validation is implemented by suppressing errors rather than by 1542 * skipping the input processing and validation steps entirely, because some 1543 * forms have button-level submit handlers that call Drupal API functions that 1544 * assume that certain data exists within $form_state['values'], and while not 1545 * doing anything with that data that requires it to be valid, PHP errors 1546 * would be triggered if the input processing and validation steps were fully 1547 * skipped. 1548 * 1549 * @param $name 1550 * The name of the form element. If the #parents property of your form 1551 * element is array('foo', 'bar', 'baz') then you may set an error on 'foo' 1552 * or 'foo][bar][baz'. Setting an error on 'foo' sets an error for every 1553 * element where the #parents array starts with 'foo'. 1554 * @param $message 1555 * The error message to present to the user. 1556 * @param $limit_validation_errors 1557 * Internal use only. The #limit_validation_errors property of the clicked 1558 * button, if it exists. 1559 * 1560 * @return 1561 * Return value is for internal use only. To get a list of errors, use 1562 * form_get_errors() or form_get_error(). 1563 * 1564 * @see http://drupal.org/node/370537 1565 * @see http://drupal.org/node/763376 1566 */ 1567 function form_set_error($name = NULL, $message = '', $limit_validation_errors = NULL) { 1568 $form = &drupal_static(__FUNCTION__, array()); 1569 $sections = &drupal_static(__FUNCTION__ . ':limit_validation_errors'); 1570 if (isset($limit_validation_errors)) { 1571 $sections = $limit_validation_errors; 1572 } 1573 1574 if (isset($name) && !isset($form[$name])) { 1575 $record = TRUE; 1576 if (isset($sections)) { 1577 // #limit_validation_errors is an array of "sections" within which user 1578 // input must be valid. If the element is within one of these sections, 1579 // the error must be recorded. Otherwise, it can be suppressed. 1580 // #limit_validation_errors can be an empty array, in which case all 1581 // errors are suppressed. For example, a "Previous" button might want its 1582 // submit action to be triggered even if none of the submitted values are 1583 // valid. 1584 $record = FALSE; 1585 foreach ($sections as $section) { 1586 // Exploding by '][' reconstructs the element's #parents. If the 1587 // reconstructed #parents begin with the same keys as the specified 1588 // section, then the element's values are within the part of 1589 // $form_state['values'] that the clicked button requires to be valid, 1590 // so errors for this element must be recorded. As the exploded array 1591 // will all be strings, we need to cast every value of the section 1592 // array to string. 1593 if (array_slice(explode('][', $name), 0, count($section)) === array_map('strval', $section)) { 1594 $record = TRUE; 1595 break; 1596 } 1597 } 1598 } 1599 if ($record) { 1600 $form[$name] = $message; 1601 if ($message) { 1602 drupal_set_message($message, 'error'); 1603 } 1604 } 1605 } 1606 1607 return $form; 1608 } 1609 1610 /** 1611 * Clears all errors against all form elements made by form_set_error(). 1612 */ 1613 function form_clear_error() { 1614 drupal_static_reset('form_set_error'); 1615 } 1616 1617 /** 1618 * Returns an associative array of all errors. 1619 */ 1620 function form_get_errors() { 1621 $form = form_set_error(); 1622 if (!empty($form)) { 1623 return $form; 1624 } 1625 } 1626 1627 /** 1628 * Returns the error message filed against the given form element. 1629 * 1630 * Form errors higher up in the form structure override deeper errors as well as 1631 * errors on the element itself. 1632 */ 1633 function form_get_error($element) { 1634 $form = form_set_error(); 1635 $parents = array(); 1636 foreach ($element['#parents'] as $parent) { 1637 $parents[] = $parent; 1638 $key = implode('][', $parents); 1639 if (isset($form[$key])) { 1640 return $form[$key]; 1641 } 1642 } 1643 } 1644 1645 /** 1646 * Flags an element as having an error. 1647 */ 1648 function form_error(&$element, $message = '') { 1649 form_set_error(implode('][', $element['#parents']), $message); 1650 } 1651 1652 /** 1653 * Builds and processes all elements in the structured form array. 1654 * 1655 * Adds any required properties to each element, maps the incoming input data 1656 * to the proper elements, and executes any #process handlers attached to a 1657 * specific element. 1658 * 1659 * This is one of the three primary functions that recursively iterates a form 1660 * array. This one does it for completing the form building process. The other 1661 * two are _form_validate() (invoked via drupal_validate_form() and used to 1662 * invoke validation logic for each element) and drupal_render() (for rendering 1663 * each element). Each of these three pipelines provides ample opportunity for 1664 * modules to customize what happens. For example, during this function's life 1665 * cycle, the following functions get called for each element: 1666 * - $element['#value_callback']: A function that implements how user input is 1667 * mapped to an element's #value property. This defaults to a function named 1668 * 'form_type_TYPE_value' where TYPE is $element['#type']. 1669 * - $element['#process']: An array of functions called after user input has 1670 * been mapped to the element's #value property. These functions can be used 1671 * to dynamically add child elements: for example, for the 'date' element 1672 * type, one of the functions in this array is form_process_date(), which adds 1673 * the individual 'year', 'month', 'day', etc. child elements. These functions 1674 * can also be used to set additional properties or implement special logic 1675 * other than adding child elements: for example, for the 'fieldset' element 1676 * type, one of the functions in this array is form_process_fieldset(), which 1677 * adds the attributes and JavaScript needed to make the fieldset collapsible 1678 * if the #collapsible property is set. The #process functions are called in 1679 * preorder traversal, meaning they are called for the parent element first, 1680 * then for the child elements. 1681 * - $element['#after_build']: An array of functions called after form_builder() 1682 * is done with its processing of the element. These are called in postorder 1683 * traversal, meaning they are called for the child elements first, then for 1684 * the parent element. 1685 * There are similar properties containing callback functions invoked by 1686 * _form_validate() and drupal_render(), appropriate for those operations. 1687 * 1688 * Developers are strongly encouraged to integrate the functionality needed by 1689 * their form or module within one of these three pipelines, using the 1690 * appropriate callback property, rather than implementing their own recursive 1691 * traversal of a form array. This facilitates proper integration between 1692 * multiple modules. For example, module developers are familiar with the 1693 * relative order in which hook_form_alter() implementations and #process 1694 * functions run. A custom traversal function that affects the building of a 1695 * form is likely to not integrate with hook_form_alter() and #process in the 1696 * expected way. Also, deep recursion within PHP is both slow and memory 1697 * intensive, so it is best to minimize how often it's done. 1698 * 1699 * As stated above, each element's #process functions are executed after its 1700 * #value has been set. This enables those functions to execute conditional 1701 * logic based on the current value. However, all of form_builder() runs before 1702 * drupal_validate_form() is called, so during #process function execution, the 1703 * element's #value has not yet been validated, so any code that requires 1704 * validated values must reside within a submit handler. 1705 * 1706 * As a security measure, user input is used for an element's #value only if the 1707 * element exists within $form, is not disabled (as per the #disabled property), 1708 * and can be accessed (as per the #access property, except that forms submitted 1709 * using drupal_form_submit() bypass #access restrictions). When user input is 1710 * ignored due to #disabled and #access restrictions, the element's default 1711 * value is used. 1712 * 1713 * Because of the preorder traversal, where #process functions of an element run 1714 * before user input for its child elements is processed, and because of the 1715 * Form API security of user input processing with respect to #access and 1716 * #disabled described above, this generally means that #process functions 1717 * should not use an element's (unvalidated) #value to affect the #disabled or 1718 * #access of child elements. Use-cases where a developer may be tempted to 1719 * implement such conditional logic usually fall into one of two categories: 1720 * - Where user input from the current submission must affect the structure of a 1721 * form, including properties like #access and #disabled that affect how the 1722 * next submission needs to be processed, a multi-step workflow is needed. 1723 * This is most commonly implemented with a submit handler setting persistent 1724 * data within $form_state based on *validated* values in 1725 * $form_state['values'] and setting $form_state['rebuild']. The form building 1726 * functions must then be implemented to use the $form_state data to rebuild 1727 * the form with the structure appropriate for the new state. 1728 * - Where user input must affect the rendering of the form without affecting 1729 * its structure, the necessary conditional rendering logic should reside 1730 * within functions that run during the rendering phase (#pre_render, #theme, 1731 * #theme_wrappers, and #post_render). 1732 * 1733 * @param $form_id 1734 * A unique string identifying the form for validation, submission, 1735 * theming, and hook_form_alter functions. 1736 * @param $element 1737 * An associative array containing the structure of the current element. 1738 * @param $form_state 1739 * A keyed array containing the current state of the form. In this 1740 * context, it is used to accumulate information about which button 1741 * was clicked when the form was submitted, as well as the sanitized 1742 * $_POST data. 1743 */ 1744 function form_builder($form_id, &$element, &$form_state) { 1745 // Initialize as unprocessed. 1746 $element['#processed'] = FALSE; 1747 1748 // Use element defaults. 1749 if (isset($element['#type']) && empty($element['#defaults_loaded']) && ($info = element_info($element['#type']))) { 1750 // Overlay $info onto $element, retaining preexisting keys in $element. 1751 $element += $info; 1752 $element['#defaults_loaded'] = TRUE; 1753 } 1754 // Assign basic defaults common for all form elements. 1755 $element += array( 1756 '#required' => FALSE, 1757 '#attributes' => array(), 1758 '#title_display' => 'before', 1759 ); 1760 1761 // Special handling if we're on the top level form element. 1762 if (isset($element['#type']) && $element['#type'] == 'form') { 1763 if (!empty($element['#https']) && variable_get('https', FALSE) && 1764 !url_is_external($element['#action'])) { 1765 global $base_root; 1766 1767 // Not an external URL so ensure that it is secure. 1768 $element['#action'] = str_replace('http://', 'https://', $base_root) . $element['#action']; 1769 } 1770 1771 // Store a reference to the complete form in $form_state prior to building 1772 // the form. This allows advanced #process and #after_build callbacks to 1773 // perform changes elsewhere in the form. 1774 $form_state['complete form'] = &$element; 1775 1776 // Set a flag if we have a correct form submission. This is always TRUE for 1777 // programmed forms coming from drupal_form_submit(), or if the form_id coming 1778 // from the POST data is set and matches the current form_id. 1779 if ($form_state['programmed'] || (!empty($form_state['input']) && (isset($form_state['input']['form_id']) && ($form_state['input']['form_id'] == $form_id)))) { 1780 $form_state['process_input'] = TRUE; 1781 } 1782 else { 1783 $form_state['process_input'] = FALSE; 1784 } 1785 1786 // All form elements should have an #array_parents property. 1787 $element['#array_parents'] = array(); 1788 } 1789 1790 if (!isset($element['#id'])) { 1791 $element['#id'] = drupal_html_id('edit-' . implode('-', $element['#parents'])); 1792 } 1793 // Handle input elements. 1794 if (!empty($element['#input'])) { 1795 _form_builder_handle_input_element($form_id, $element, $form_state); 1796 } 1797 // Allow for elements to expand to multiple elements, e.g., radios, 1798 // checkboxes and files. 1799 if (isset($element['#process']) && !$element['#processed']) { 1800 foreach ($element['#process'] as $process) { 1801 $element = $process($element, $form_state, $form_state['complete form']); 1802 } 1803 $element['#processed'] = TRUE; 1804 } 1805 1806 // We start off assuming all form elements are in the correct order. 1807 $element['#sorted'] = TRUE; 1808 1809 // Recurse through all child elements. 1810 $count = 0; 1811 foreach (element_children($element) as $key) { 1812 // Prior to checking properties of child elements, their default properties 1813 // need to be loaded. 1814 if (isset($element[$key]['#type']) && empty($element[$key]['#defaults_loaded']) && ($info = element_info($element[$key]['#type']))) { 1815 $element[$key] += $info; 1816 $element[$key]['#defaults_loaded'] = TRUE; 1817 } 1818 1819 // Don't squash an existing tree value. 1820 if (!isset($element[$key]['#tree'])) { 1821 $element[$key]['#tree'] = $element['#tree']; 1822 } 1823 1824 // Deny access to child elements if parent is denied. 1825 if (isset($element['#access']) && !$element['#access']) { 1826 $element[$key]['#access'] = FALSE; 1827 } 1828 1829 // Make child elements inherit their parent's #disabled and #allow_focus 1830 // values unless they specify their own. 1831 foreach (array('#disabled', '#allow_focus') as $property) { 1832 if (isset($element[$property]) && !isset($element[$key][$property])) { 1833 $element[$key][$property] = $element[$property]; 1834 } 1835 } 1836 1837 // Don't squash existing parents value. 1838 if (!isset($element[$key]['#parents'])) { 1839 // Check to see if a tree of child elements is present. If so, 1840 // continue down the tree if required. 1841 $element[$key]['#parents'] = $element[$key]['#tree'] && $element['#tree'] ? array_merge($element['#parents'], array($key)) : array($key); 1842 } 1843 // Ensure #array_parents follows the actual form structure. 1844 $array_parents = $element['#array_parents']; 1845 $array_parents[] = $key; 1846 $element[$key]['#array_parents'] = $array_parents; 1847 1848 // Assign a decimal placeholder weight to preserve original array order. 1849 if (!isset($element[$key]['#weight'])) { 1850 $element[$key]['#weight'] = $count/1000; 1851 } 1852 else { 1853 // If one of the child elements has a weight then we will need to sort 1854 // later. 1855 unset($element['#sorted']); 1856 } 1857 $element[$key] = form_builder($form_id, $element[$key], $form_state); 1858 $count++; 1859 } 1860 1861 // The #after_build flag allows any piece of a form to be altered 1862 // after normal input parsing has been completed. 1863 if (isset($element['#after_build']) && !isset($element['#after_build_done'])) { 1864 foreach ($element['#after_build'] as $function) { 1865 $element = $function($element, $form_state); 1866 } 1867 $element['#after_build_done'] = TRUE; 1868 } 1869 1870 // If there is a file element, we need to flip a flag so later the 1871 // form encoding can be set. 1872 if (isset($element['#type']) && $element['#type'] == 'file') { 1873 $form_state['has_file_element'] = TRUE; 1874 } 1875 1876 // Final tasks for the form element after form_builder() has run for all other 1877 // elements. 1878 if (isset($element['#type']) && $element['#type'] == 'form') { 1879 // If there is a file element, we set the form encoding. 1880 if (isset($form_state['has_file_element'])) { 1881 $element['#attributes']['enctype'] = 'multipart/form-data'; 1882 } 1883 1884 // If a form contains a single textfield, and the ENTER key is pressed 1885 // within it, Internet Explorer submits the form with no POST data 1886 // identifying any submit button. Other browsers submit POST data as though 1887 // the user clicked the first button. Therefore, to be as consistent as we 1888 // can be across browsers, if no 'triggering_element' has been identified 1889 // yet, default it to the first button. 1890 if (!$form_state['programmed'] && !isset($form_state['triggering_element']) && !empty($form_state['buttons'])) { 1891 $form_state['triggering_element'] = $form_state['buttons'][0]; 1892 } 1893 1894 // If the triggering element specifies "button-level" validation and submit 1895 // handlers to run instead of the default form-level ones, then add those to 1896 // the form state. 1897 foreach (array('validate', 'submit') as $type) { 1898 if (isset($form_state['triggering_element']['#' . $type])) { 1899 $form_state[$type . '_handlers'] = $form_state['triggering_element']['#' . $type]; 1900 } 1901 } 1902 1903 // If the triggering element executes submit handlers, then set the form 1904 // state key that's needed for those handlers to run. 1905 if (!empty($form_state['triggering_element']['#executes_submit_callback'])) { 1906 $form_state['submitted'] = TRUE; 1907 } 1908 1909 // Special processing if the triggering element is a button. 1910 if (isset($form_state['triggering_element']['#button_type'])) { 1911 // Because there are several ways in which the triggering element could 1912 // have been determined (including from input variables set by JavaScript 1913 // or fallback behavior implemented for IE), and because buttons often 1914 // have their #name property not derived from their #parents property, we 1915 // can't assume that input processing that's happened up until here has 1916 // resulted in $form_state['values'][BUTTON_NAME] being set. But it's 1917 // common for forms to have several buttons named 'op' and switch on 1918 // $form_state['values']['op'] during submit handler execution. 1919 $form_state['values'][$form_state['triggering_element']['#name']] = $form_state['triggering_element']['#value']; 1920 1921 // @todo Legacy support. Remove in Drupal 8. 1922 $form_state['clicked_button'] = $form_state['triggering_element']; 1923 } 1924 } 1925 return $element; 1926 } 1927 1928 /** 1929 * Adds the #name and #value properties of an input element before rendering. 1930 */ 1931 function _form_builder_handle_input_element($form_id, &$element, &$form_state) { 1932 if (!isset($element['#name'])) { 1933 $name = array_shift($element['#parents']); 1934 $element['#name'] = $name; 1935 if ($element['#type'] == 'file') { 1936 // To make it easier to handle $_FILES in file.inc, we place all 1937 // file fields in the 'files' array. Also, we do not support 1938 // nested file names. 1939 $element['#name'] = 'files[' . $element['#name'] . ']'; 1940 } 1941 elseif (count($element['#parents'])) { 1942 $element['#name'] .= '[' . implode('][', $element['#parents']) . ']'; 1943 } 1944 array_unshift($element['#parents'], $name); 1945 } 1946 1947 // Setting #disabled to TRUE results in user input being ignored, regardless 1948 // of how the element is themed or whether JavaScript is used to change the 1949 // control's attributes. However, it's good UI to let the user know that input 1950 // is not wanted for the control. HTML supports two attributes for this: 1951 // http://www.w3.org/TR/html401/interact/forms.html#h-17.12. If a form wants 1952 // to start a control off with one of these attributes for UI purposes only, 1953 // but still allow input to be processed if it's sumitted, it can set the 1954 // desired attribute in #attributes directly rather than using #disabled. 1955 // However, developers should think carefully about the accessibility 1956 // implications of doing so: if the form expects input to be enterable under 1957 // some condition triggered by JavaScript, how would someone who has 1958 // JavaScript disabled trigger that condition? Instead, developers should 1959 // consider whether a multi-step form would be more appropriate (#disabled can 1960 // be changed from step to step). If one still decides to use JavaScript to 1961 // affect when a control is enabled, then it is best for accessibility for the 1962 // control to be enabled in the HTML, and disabled by JavaScript on document 1963 // ready. 1964 if (!empty($element['#disabled'])) { 1965 if (!empty($element['#allow_focus'])) { 1966 $element['#attributes']['readonly'] = 'readonly'; 1967 } 1968 else { 1969 $element['#attributes']['disabled'] = 'disabled'; 1970 } 1971 } 1972 1973 // With JavaScript or other easy hacking, input can be submitted even for 1974 // elements with #access=FALSE or #disabled=TRUE. For security, these must 1975 // not be processed. Forms that set #disabled=TRUE on an element do not 1976 // expect input for the element, and even forms submitted with 1977 // drupal_form_submit() must not be able to get around this. Forms that set 1978 // #access=FALSE on an element usually allow access for some users, so forms 1979 // submitted with drupal_form_submit() may bypass access restriction and be 1980 // treated as high-privilege users instead. 1981 $process_input = empty($element['#disabled']) && ($form_state['programmed'] || ($form_state['process_input'] && (!isset($element['#access']) || $element['#access']))); 1982 1983 // Set the element's #value property. 1984 if (!isset($element['#value']) && !array_key_exists('#value', $element)) { 1985 $value_callback = !empty($element['#value_callback']) ? $element['#value_callback'] : 'form_type_' . $element['#type'] . '_value'; 1986 if ($process_input) { 1987 // Get the input for the current element. NULL values in the input need to 1988 // be explicitly distinguished from missing input. (see below) 1989 $input_exists = NULL; 1990 $input = drupal_array_get_nested_value($form_state['input'], $element['#parents'], $input_exists); 1991 // For browser-submitted forms, the submitted values do not contain values 1992 // for certain elements (empty multiple select, unchecked checkbox). 1993 // During initial form processing, we add explicit NULL values for such 1994 // elements in $form_state['input']. When rebuilding the form, we can 1995 // distinguish elements having NULL input from elements that were not part 1996 // of the initially submitted form and can therefore use default values 1997 // for the latter, if required. Programmatically submitted forms can 1998 // submit explicit NULL values when calling drupal_form_submit(), so we do 1999 // not modify $form_state['input'] for them. 2000 if (!$input_exists && !$form_state['rebuild'] && !$form_state['programmed']) { 2001 // Add the necessary parent keys to $form_state['input'] and sets the 2002 // element's input value to NULL. 2003 drupal_array_set_nested_value($form_state['input'], $element['#parents'], NULL); 2004 $input_exists = TRUE; 2005 } 2006 // If we have input for the current element, assign it to the #value 2007 // property, optionally filtered through $value_callback. 2008 if ($input_exists) { 2009 if (function_exists($value_callback)) { 2010 $element['#value'] = $value_callback($element, $input, $form_state); 2011 } 2012 if (!isset($element['#value']) && isset($input)) { 2013 $element['#value'] = $input; 2014 } 2015 } 2016 // Mark all posted values for validation. 2017 if (isset($element['#value']) || (!empty($element['#required']))) { 2018 $element['#needs_validation'] = TRUE; 2019 } 2020 } 2021 // Load defaults. 2022 if (!isset($element['#value'])) { 2023 // Call #type_value without a second argument to request default_value handling. 2024 if (function_exists($value_callback)) { 2025 $element['#value'] = $value_callback($element, FALSE, $form_state); 2026 } 2027 // Final catch. If we haven't set a value yet, use the explicit default value. 2028 // Avoid image buttons (which come with garbage value), so we only get value 2029 // for the button actually clicked. 2030 if (!isset($element['#value']) && empty($element['#has_garbage_value'])) { 2031 $element['#value'] = isset($element['#default_value']) ? $element['#default_value'] : ''; 2032 } 2033 } 2034 } 2035 2036 // Determine which element (if any) triggered the submission of the form and 2037 // keep track of all the clickable buttons in the form for 2038 // form_state_values_clean(). Enforce the same input processing restrictions 2039 // as above. 2040 if ($process_input) { 2041 // Detect if the element triggered the submission via Ajax. 2042 if (_form_element_triggered_scripted_submission($element, $form_state)) { 2043 $form_state['triggering_element'] = $element; 2044 } 2045 2046 // If the form was submitted by the browser rather than via Ajax, then it 2047 // can only have been triggered by a button, and we need to determine which 2048 // button within the constraints of how browsers provide this information. 2049 if (isset($element['#button_type'])) { 2050 // All buttons in the form need to be tracked for 2051 // form_state_values_clean() and for the form_builder() code that handles 2052 // a form submission containing no button information in $_POST. 2053 $form_state['buttons'][] = $element; 2054 if (_form_button_was_clicked($element, $form_state)) { 2055 $form_state['triggering_element'] = $element; 2056 } 2057 } 2058 } 2059 2060 // Set the element's value in $form_state['values'], but only, if its key 2061 // does not exist yet (a #value_callback may have already populated it). 2062 if (!drupal_array_nested_key_exists($form_state['values'], $element['#parents'])) { 2063 form_set_value($element, $element['#value'], $form_state); 2064 } 2065 } 2066 2067 /** 2068 * Detects if an element triggered the form submission via Ajax. 2069 * 2070 * This detects button or non-button controls that trigger a form submission via 2071 * Ajax or some other scriptable environment. These environments can set the 2072 * special input key '_triggering_element_name' to identify the triggering 2073 * element. If the name alone doesn't identify the element uniquely, the input 2074 * key '_triggering_element_value' may also be set to require a match on element 2075 * value. An example where this is needed is if there are several buttons all 2076 * named 'op', and only differing in their value. 2077 */ 2078 function _form_element_triggered_scripted_submission($element, &$form_state) { 2079 if (!empty($form_state['input']['_triggering_element_name']) && $element['#name'] == $form_state['input']['_triggering_element_name']) { 2080 if (empty($form_state['input']['_triggering_element_value']) || $form_state['input']['_triggering_element_value'] == $element['#value']) { 2081 return TRUE; 2082 } 2083 } 2084 return FALSE; 2085 } 2086 2087 /** 2088 * Determines if a given button triggered the form submission. 2089 * 2090 * This detects button controls that trigger a form submission by being clicked 2091 * and having the click processed by the browser rather than being captured by 2092 * JavaScript. Essentially, it detects if the button's name and value are part 2093 * of the POST data, but with extra code to deal with the convoluted way in 2094 * which browsers submit data for image button clicks. 2095 * 2096 * This does not detect button clicks processed by Ajax (that is done in 2097 * _form_element_triggered_scripted_submission()) and it does not detect form 2098 * submissions from Internet Explorer in response to an ENTER key pressed in a 2099 * textfield (form_builder() has extra code for that). 2100 * 2101 * Because this function contains only part of the logic needed to determine 2102 * $form_state['triggering_element'], it should not be called from anywhere 2103 * other than within the Form API. Form validation and submit handlers needing 2104 * to know which button was clicked should get that information from 2105 * $form_state['triggering_element']. 2106 */ 2107 function _form_button_was_clicked($element, &$form_state) { 2108 // First detect normal 'vanilla' button clicks. Traditionally, all 2109 // standard buttons on a form share the same name (usually 'op'), 2110 // and the specific return value is used to determine which was 2111 // clicked. This ONLY works as long as $form['#name'] puts the 2112 // value at the top level of the tree of $_POST data. 2113 if (isset($form_state['input'][$element['#name']]) && $form_state['input'][$element['#name']] == $element['#value']) { 2114 return TRUE; 2115 } 2116 // When image buttons are clicked, browsers do NOT pass the form element 2117 // value in $_POST. Instead they pass an integer representing the 2118 // coordinates of the click on the button image. This means that image 2119 // buttons MUST have unique $form['#name'] values, but the details of 2120 // their $_POST data should be ignored. 2121 elseif (!empty($element['#has_garbage_value']) && isset($element['#value']) && $element['#value'] !== '') { 2122 return TRUE; 2123 } 2124 return FALSE; 2125 } 2126 2127 /** 2128 * Removes internal Form API elements and buttons from submitted form values. 2129 * 2130 * This function can be used when a module wants to store all submitted form 2131 * values, for example, by serializing them into a single database column. In 2132 * such cases, all internal Form API values and all form button elements should 2133 * not be contained, and this function allows to remove them before the module 2134 * proceeds to storage. Next to button elements, the following internal values 2135 * are removed: 2136 * - form_id 2137 * - form_token 2138 * - form_build_id 2139 * - op 2140 * 2141 * @param $form_state 2142 * A keyed array containing the current state of the form, including 2143 * submitted form values; altered by reference. 2144 */ 2145 function form_state_values_clean(&$form_state) { 2146 // Remove internal Form API values. 2147 unset($form_state['values']['form_id'], $form_state['values']['form_token'], $form_state['values']['form_build_id'], $form_state['values']['op']); 2148 2149 // Remove button values. 2150 // form_builder() collects all button elements in a form. We remove the button 2151 // value separately for each button element. 2152 foreach ($form_state['buttons'] as $button) { 2153 // Remove this button's value from the submitted form values by finding 2154 // the value corresponding to this button. 2155 // We iterate over the #parents of this button and move a reference to 2156 // each parent in $form_state['values']. For example, if #parents is: 2157 // array('foo', 'bar', 'baz') 2158 // then the corresponding $form_state['values'] part will look like this: 2159 // array( 2160 // 'foo' => array( 2161 // 'bar' => array( 2162 // 'baz' => 'button_value', 2163 // ), 2164 // ), 2165 // ) 2166 // We start by (re)moving 'baz' to $last_parent, so we are able unset it 2167 // at the end of the iteration. Initially, $values will contain a 2168 // reference to $form_state['values'], but in the iteration we move the 2169 // reference to $form_state['values']['foo'], and finally to 2170 // $form_state['values']['foo']['bar'], which is the level where we can 2171 // unset 'baz' (that is stored in $last_parent). 2172 $parents = $button['#parents']; 2173 $last_parent = array_pop($parents); 2174 $key_exists = NULL; 2175 $values = &drupal_array_get_nested_value($form_state['values'], $parents, $key_exists); 2176 if ($key_exists && is_array($values)) { 2177 unset($values[$last_parent]); 2178 } 2179 } 2180 } 2181 2182 /** 2183 * Determines the value for an image button form element. 2184 * 2185 * @param $form 2186 * The form element whose value is being populated. 2187 * @param $input 2188 * The incoming input to populate the form element. If this is FALSE, 2189 * the element's default value should be returned. 2190 * @param $form_state 2191 * A keyed array containing the current state of the form. 2192 * 2193 * @return 2194 * The data that will appear in the $form_state['values'] collection 2195 * for this element. Return nothing to use the default. 2196 */ 2197 function form_type_image_button_value($form, $input, $form_state) { 2198 if ($input !== FALSE) { 2199 if (!empty($input)) { 2200 // If we're dealing with Mozilla or Opera, we're lucky. It will 2201 // return a proper value, and we can get on with things. 2202 return $form['#return_value']; 2203 } 2204 else { 2205 // Unfortunately, in IE we never get back a proper value for THIS 2206 // form element. Instead, we get back two split values: one for the 2207 // X and one for the Y coordinates on which the user clicked the 2208 // button. We'll find this element in the #post data, and search 2209 // in the same spot for its name, with '_x'. 2210 $input = $form_state['input']; 2211 foreach (explode('[', $form['#name']) as $element_name) { 2212 // chop off the ] that may exist. 2213 if (substr($element_name, -1) == ']') { 2214 $element_name = substr($element_name, 0, -1); 2215 } 2216 2217 if (!isset($input[$element_name])) { 2218 if (isset($input[$element_name . '_x'])) { 2219 return $form['#return_value']; 2220 } 2221 return NULL; 2222 } 2223 $input = $input[$element_name]; 2224 } 2225 return $form['#return_value']; 2226 } 2227 } 2228 } 2229 2230 /** 2231 * Determines the value for a checkbox form element. 2232 * 2233 * @param $form 2234 * The form element whose value is being populated. 2235 * @param $input 2236 * The incoming input to populate the form element. If this is FALSE, 2237 * the element's default value should be returned. 2238 * 2239 * @return 2240 * The data that will appear in the $element_state['values'] collection 2241 * for this element. Return nothing to use the default. 2242 */ 2243 function form_type_checkbox_value($element, $input = FALSE) { 2244 if ($input === FALSE) { 2245 // Use #default_value as the default value of a checkbox, except change 2246 // NULL to 0, because _form_builder_handle_input_element() would otherwise 2247 // replace NULL with empty string, but an empty string is a potentially 2248 // valid value for a checked checkbox. 2249 return isset($element['#default_value']) ? $element['#default_value'] : 0; 2250 } 2251 else { 2252 // Checked checkboxes are submitted with a value (possibly '0' or ''): 2253 // http://www.w3.org/TR/html401/interact/forms.html#successful-controls. 2254 // For checked checkboxes, browsers submit the string version of 2255 // #return_value, but we return the original #return_value. For unchecked 2256 // checkboxes, browsers submit nothing at all, but 2257 // _form_builder_handle_input_element() detects this, and calls this 2258 // function with $input=NULL. Returning NULL from a value callback means to 2259 // use the default value, which is not what is wanted when an unchecked 2260 // checkbox is submitted, so we use integer 0 as the value indicating an 2261 // unchecked checkbox. Therefore, modules must not use integer 0 as a 2262 // #return_value, as doing so results in the checkbox always being treated 2263 // as unchecked. The string '0' is allowed for #return_value. The most 2264 // common use-case for setting #return_value to either 0 or '0' is for the 2265 // first option within a 0-indexed array of checkboxes, and for this, 2266 // form_process_checkboxes() uses the string rather than the integer. 2267 return isset($input) ? $element['#return_value'] : 0; 2268 } 2269 } 2270 2271 /** 2272 * Determines the value for a checkboxes form element. 2273 * 2274 * @param $element 2275 * The form element whose value is being populated. 2276 * @param $input 2277 * The incoming input to populate the form element. If this is FALSE, 2278 * the element's default value should be returned. 2279 * 2280 * @return 2281 * The data that will appear in the $element_state['values'] collection 2282 * for this element. Return nothing to use the default. 2283 */ 2284 function form_type_checkboxes_value($element, $input = FALSE) { 2285 if ($input === FALSE) { 2286 $value = array(); 2287 $element += array('#default_value' => array()); 2288 foreach ($element['#default_value'] as $key) { 2289 $value[$key] = $key; 2290 } 2291 return $value; 2292 } 2293 elseif (is_array($input)) { 2294 // Programmatic form submissions use NULL to indicate that a checkbox 2295 // should be unchecked; see drupal_form_submit(). We therefore remove all 2296 // NULL elements from the array before constructing the return value, to 2297 // simulate the behavior of web browsers (which do not send unchecked 2298 // checkboxes to the server at all). This will not affect non-programmatic 2299 // form submissions, since all values in $_POST are strings. 2300 foreach ($input as $key => $value) { 2301 if (!isset($value)) { 2302 unset($input[$key]); 2303 } 2304 } 2305 return drupal_map_assoc($input); 2306 } 2307 else { 2308 return array(); 2309 } 2310 } 2311 2312 /** 2313 * Determines the value for a tableselect form element. 2314 * 2315 * @param $element 2316 * The form element whose value is being populated. 2317 * @param $input 2318 * The incoming input to populate the form element. If this is FALSE, 2319 * the element's default value should be returned. 2320 * 2321 * @return 2322 * The data that will appear in the $element_state['values'] collection 2323 * for this element. Return nothing to use the default. 2324 */ 2325 function form_type_tableselect_value($element, $input = FALSE) { 2326 // If $element['#multiple'] == FALSE, then radio buttons are displayed and 2327 // the default value handling is used. 2328 if (isset($element['#multiple']) && $element['#multiple']) { 2329 // Checkboxes are being displayed with the default value coming from the 2330 // keys of the #default_value property. This differs from the checkboxes 2331 // element which uses the array values. 2332 if ($input === FALSE) { 2333 $value = array(); 2334 $element += array('#default_value' => array()); 2335 foreach ($element['#default_value'] as $key => $flag) { 2336 if ($flag) { 2337 $value[$key] = $key; 2338 } 2339 } 2340 return $value; 2341 } 2342 else { 2343 return is_array($input) ? drupal_map_assoc($input) : array(); 2344 } 2345 } 2346 } 2347 2348 /** 2349 * Form value callback: Determines the value for a #type radios form element. 2350 * 2351 * @param $element 2352 * The form element whose value is being populated. 2353 * @param $input 2354 * (optional) The incoming input to populate the form element. If FALSE, the 2355 * element's default value is returned. Defaults to FALSE. 2356 * 2357 * @return 2358 * The data that will appear in the $element_state['values'] collection for 2359 * this element. 2360 */ 2361 function form_type_radios_value(&$element, $input = FALSE) { 2362 if ($input !== FALSE) { 2363 // When there's user input (including NULL), return it as the value. 2364 // However, if NULL is submitted, _form_builder_handle_input_element() will 2365 // apply the default value, and we want that validated against #options 2366 // unless it's empty. (An empty #default_value, such as NULL or FALSE, can 2367 // be used to indicate that no radio button is selected by default.) 2368 if (!isset($input) && !empty($element['#default_value'])) { 2369 $element['#needs_validation'] = TRUE; 2370 } 2371 return $input; 2372 } 2373 else { 2374 // For default value handling, simply return #default_value. Additionally, 2375 // for a NULL default value, set #has_garbage_value to prevent 2376 // _form_builder_handle_input_element() converting the NULL to an empty 2377 // string, so that code can distinguish between nothing selected and the 2378 // selection of a radio button whose value is an empty string. 2379 $value = isset($element['#default_value']) ? $element['#default_value'] : NULL; 2380 if (!isset($value)) { 2381 $element['#has_garbage_value'] = TRUE; 2382 } 2383 return $value; 2384 } 2385 } 2386 2387 /** 2388 * Determines the value for a password_confirm form element. 2389 * 2390 * @param $element 2391 * The form element whose value is being populated. 2392 * @param $input 2393 * The incoming input to populate the form element. If this is FALSE, 2394 * the element's default value should be returned. 2395 * 2396 * @return 2397 * The data that will appear in the $element_state['values'] collection 2398 * for this element. Return nothing to use the default. 2399 */ 2400 function form_type_password_confirm_value($element, $input = FALSE) { 2401 if ($input === FALSE) { 2402 $element += array('#default_value' => array()); 2403 return $element['#default_value'] + array('pass1' => '', 'pass2' => ''); 2404 } 2405 } 2406 2407 /** 2408 * Determines the value for a select form element. 2409 * 2410 * @param $element 2411 * The form element whose value is being populated. 2412 * @param $input 2413 * The incoming input to populate the form element. If this is FALSE, 2414 * the element's default value should be returned. 2415 * 2416 * @return 2417 * The data that will appear in the $element_state['values'] collection 2418 * for this element. Return nothing to use the default. 2419 */ 2420 function form_type_select_value($element, $input = FALSE) { 2421 if ($input !== FALSE) { 2422 if (isset($element['#multiple']) && $element['#multiple']) { 2423 // If an enabled multi-select submits NULL, it means all items are 2424 // unselected. A disabled multi-select always submits NULL, and the 2425 // default value should be used. 2426 if (empty($element['#disabled'])) { 2427 return (is_array($input)) ? drupal_map_assoc($input) : array(); 2428 } 2429 else { 2430 return (isset($element['#default_value']) && is_array($element['#default_value'])) ? $element['#default_value'] : array(); 2431 } 2432 } 2433 // Non-multiple select elements may have an empty option preprended to them 2434 // (see form_process_select()). When this occurs, usually #empty_value is 2435 // an empty string, but some forms set #empty_value to integer 0 or some 2436 // other non-string constant. PHP receives all submitted form input as 2437 // strings, but if the empty option is selected, set the value to match the 2438 // empty value exactly. 2439 elseif (isset($element['#empty_value']) && $input === (string) $element['#empty_value']) { 2440 return $element['#empty_value']; 2441 } 2442 else { 2443 return $input; 2444 } 2445 } 2446 } 2447 2448 /** 2449 * Determines the value for a textfield form element. 2450 * 2451 * @param $element 2452 * The form element whose value is being populated. 2453 * @param $input 2454 * The incoming input to populate the form element. If this is FALSE, 2455 * the element's default value should be returned. 2456 * 2457 * @return 2458 * The data that will appear in the $element_state['values'] collection 2459 * for this element. Return nothing to use the default. 2460 */ 2461 function form_type_textfield_value($element, $input = FALSE) { 2462 if ($input !== FALSE && $input !== NULL) { 2463 // Equate $input to the form value to ensure it's marked for 2464 // validation. 2465 return str_replace(array("\r", "\n"), '', $input); 2466 } 2467 } 2468 2469 /** 2470 * Determines the value for form's token value. 2471 * 2472 * @param $element 2473 * The form element whose value is being populated. 2474 * @param $input 2475 * The incoming input to populate the form element. If this is FALSE, 2476 * the element's default value should be returned. 2477 * 2478 * @return 2479 * The data that will appear in the $element_state['values'] collection 2480 * for this element. Return nothing to use the default. 2481 */ 2482 function form_type_token_value($element, $input = FALSE) { 2483 if ($input !== FALSE) { 2484 return (string) $input; 2485 } 2486 } 2487 2488 /** 2489 * Changes submitted form values during form validation. 2490 * 2491 * Use this function to change the submitted value of a form element in a form 2492 * validation function, so that the changed value persists in $form_state 2493 * through the remaining validation and submission handlers. It does not change 2494 * the value in $element['#value'], only in $form_state['values'], which is 2495 * where submitted values are always stored. 2496 * 2497 * Note that form validation functions are specified in the '#validate' 2498 * component of the form array (the value of $form['#validate'] is an array of 2499 * validation function names). If the form does not originate in your module, 2500 * you can implement hook_form_FORM_ID_alter() to add a validation function 2501 * to $form['#validate']. 2502 * 2503 * @param $element 2504 * The form element that should have its value updated; in most cases you can 2505 * just pass in the element from the $form array, although the only component 2506 * that is actually used is '#parents'. If constructing yourself, set 2507 * $element['#parents'] to be an array giving the path through the form 2508 * array's keys to the element whose value you want to update. For instance, 2509 * if you want to update the value of $form['elem1']['elem2'], which should be 2510 * stored in $form_state['values']['elem1']['elem2'], you would set 2511 * $element['#parents'] = array('elem1','elem2'). 2512 * @param $value 2513 * The new value for the form element. 2514 * @param $form_state 2515 * Form state array where the value change should be recorded. 2516 */ 2517 function form_set_value($element, $value, &$form_state) { 2518 drupal_array_set_nested_value($form_state['values'], $element['#parents'], $value, TRUE); 2519 } 2520 2521 /** 2522 * Allows PHP array processing of multiple select options with the same value. 2523 * 2524 * Used for form select elements which need to validate HTML option groups 2525 * and multiple options which may return the same value. Associative PHP arrays 2526 * cannot handle these structures, since they share a common key. 2527 * 2528 * @param $array 2529 * The form options array to process. 2530 * 2531 * @return 2532 * An array with all hierarchical elements flattened to a single array. 2533 */ 2534 function form_options_flatten($array) { 2535 // Always reset static var when first entering the recursion. 2536 drupal_static_reset('_form_options_flatten'); 2537 return _form_options_flatten($array); 2538 } 2539 2540 /** 2541 * Iterates over an array and returns a flat array with duplicate keys removed. 2542 * 2543 * This function also handles cases where objects are passed as array values. 2544 */ 2545 function _form_options_flatten($array) { 2546 $return = &drupal_static(__FUNCTION__); 2547 2548 foreach ($array as $key => $value) { 2549 if (is_object($value)) { 2550 _form_options_flatten($value->option); 2551 } 2552 elseif (is_array($value)) { 2553 _form_options_flatten($value); 2554 } 2555 else { 2556 $return[$key] = 1; 2557 } 2558 } 2559 2560 return $return; 2561 } 2562 2563 /** 2564 * Processes a select list form element. 2565 * 2566 * This process callback is mandatory for select fields, since all user agents 2567 * automatically preselect the first available option of single (non-multiple) 2568 * select lists. 2569 * 2570 * @param $element 2571 * The form element to process. Properties used: 2572 * - #multiple: (optional) Indicates whether one or more options can be 2573 * selected. Defaults to FALSE. 2574 * - #default_value: Must be NULL or not set in case there is no value for the 2575 * element yet, in which case a first default option is inserted by default. 2576 * Whether this first option is a valid option depends on whether the field 2577 * is #required or not. 2578 * - #required: (optional) Whether the user needs to select an option (TRUE) 2579 * or not (FALSE). Defaults to FALSE. 2580 * - #empty_option: (optional) The label to show for the first default option. 2581 * By default, the label is automatically set to "- Please select -" for a 2582 * required field and "- None -" for an optional field. 2583 * - #empty_value: (optional) The value for the first default option, which is 2584 * used to determine whether the user submitted a value or not. 2585 * - If #required is TRUE, this defaults to '' (an empty string). 2586 * - If #required is not TRUE and this value isn't set, then no extra option 2587 * is added to the select control, leaving the control in a slightly 2588 * illogical state, because there's no way for the user to select nothing, 2589 * since all user agents automatically preselect the first available 2590 * option. But people are used to this being the behavior of select 2591 * controls. 2592 * @todo Address the above issue in Drupal 8. 2593 * - If #required is not TRUE and this value is set (most commonly to an 2594 * empty string), then an extra option (see #empty_option above) 2595 * representing a "non-selection" is added with this as its value. 2596 * 2597 * @see _form_validate() 2598 */ 2599 function form_process_select($element) { 2600 // #multiple select fields need a special #name. 2601 if ($element['#multiple']) { 2602 $element['#attributes']['multiple'] = 'multiple'; 2603 $element['#attributes']['name'] = $element['#name'] . '[]'; 2604 } 2605 // A non-#multiple select needs special handling to prevent user agents from 2606 // preselecting the first option without intention. #multiple select lists do 2607 // not get an empty option, as it would not make sense, user interface-wise. 2608 else { 2609 $required = $element['#required']; 2610 // If the element is required and there is no #default_value, then add an 2611 // empty option that will fail validation, so that the user is required to 2612 // make a choice. Also, if there's a value for #empty_value or 2613 // #empty_option, then add an option that represents emptiness. 2614 if (($required && !isset($element['#default_value'])) || isset($element['#empty_value']) || isset($element['#empty_option'])) { 2615 $element += array( 2616 '#empty_value' => '', 2617 '#empty_option' => $required ? t('- Select -') : t('- None -'), 2618 ); 2619 // The empty option is prepended to #options and purposively not merged 2620 // to prevent another option in #options mistakenly using the same value 2621 // as #empty_value. 2622 $empty_option = array($element['#empty_value'] => $element['#empty_option']); 2623 $element['#options'] = $empty_option + $element['#options']; 2624 } 2625 } 2626 return $element; 2627 } 2628 2629 /** 2630 * Returns HTML for a select form element. 2631 * 2632 * It is possible to group options together; to do this, change the format of 2633 * $options to an associative array in which the keys are group labels, and the 2634 * values are associative arrays in the normal $options format. 2635 * 2636 * @param $variables 2637 * An associative array containing: 2638 * - element: An associative array containing the properties of the element. 2639 * Properties used: #title, #value, #options, #description, #extra, 2640 * #multiple, #required, #name, #attributes, #size. 2641 * 2642 * @ingroup themeable 2643 */ 2644 function theme_select($variables) { 2645 $element = $variables['element']; 2646 element_set_attributes($element, array('id', 'name', 'size')); 2647 _form_set_class($element, array('form-select')); 2648 2649 return '<select' . drupal_attributes($element['#attributes']) . '>' . form_select_options($element) . '</select>'; 2650 } 2651 2652 /** 2653 * Converts a select form element's options array into HTML. 2654 * 2655 * @param $element 2656 * An associative array containing the properties of the element. 2657 * @param $choices 2658 * Mixed: Either an associative array of items to list as choices, or an 2659 * object with an 'option' member that is an associative array. This 2660 * parameter is only used internally and should not be passed. 2661 * 2662 * @return 2663 * An HTML string of options for the select form element. 2664 */ 2665 function form_select_options($element, $choices = NULL) { 2666 if (!isset($choices)) { 2667 $choices = $element['#options']; 2668 } 2669 // array_key_exists() accommodates the rare event where $element['#value'] is NULL. 2670 // isset() fails in this situation. 2671 $value_valid = isset($element['#value']) || array_key_exists('#value', $element); 2672 $value_is_array = $value_valid && is_array($element['#value']); 2673 $options = ''; 2674 foreach ($choices as $key => $choice) { 2675 if (is_array($choice)) { 2676 $options .= '<optgroup label="' . $key . '">'; 2677 $options .= form_select_options($element, $choice); 2678 $options .= '</optgroup>'; 2679 } 2680 elseif (is_object($choice)) { 2681 $options .= form_select_options($element, $choice->option); 2682 } 2683 else { 2684 $key = (string) $key; 2685 if ($value_valid && (!$value_is_array && (string) $element['#value'] === $key || ($value_is_array && in_array($key, $element['#value'])))) { 2686 $selected = ' selected="selected"'; 2687 } 2688 else { 2689 $selected = ''; 2690 } 2691 $options .= '<option value="' . check_plain($key) . '"' . $selected . '>' . check_plain($choice) . '</option>'; 2692 } 2693 } 2694 return $options; 2695 } 2696 2697 /** 2698 * Returns the indexes of a select element's options matching a given key. 2699 * 2700 * This function is useful if you need to modify the options that are 2701 * already in a form element; for example, to remove choices which are 2702 * not valid because of additional filters imposed by another module. 2703 * One example might be altering the choices in a taxonomy selector. 2704 * To correctly handle the case of a multiple hierarchy taxonomy, 2705 * #options arrays can now hold an array of objects, instead of a 2706 * direct mapping of keys to labels, so that multiple choices in the 2707 * selector can have the same key (and label). This makes it difficult 2708 * to manipulate directly, which is why this helper function exists. 2709 * 2710 * This function does not support optgroups (when the elements of the 2711 * #options array are themselves arrays), and will return FALSE if 2712 * arrays are found. The caller must either flatten/restore or 2713 * manually do their manipulations in this case, since returning the 2714 * index is not sufficient, and supporting this would make the 2715 * "helper" too complicated and cumbersome to be of any help. 2716 * 2717 * As usual with functions that can return array() or FALSE, do not 2718 * forget to use === and !== if needed. 2719 * 2720 * @param $element 2721 * The select element to search. 2722 * @param $key 2723 * The key to look for. 2724 * 2725 * @return 2726 * An array of indexes that match the given $key. Array will be 2727 * empty if no elements were found. FALSE if optgroups were found. 2728 */ 2729 function form_get_options($element, $key) { 2730 $keys = array(); 2731 foreach ($element['#options'] as $index => $choice) { 2732 if (is_array($choice)) { 2733 return FALSE; 2734 } 2735 elseif (is_object($choice)) { 2736 if (isset($choice->option[$key])) { 2737 $keys[] = $index; 2738 } 2739 } 2740 elseif ($index == $key) { 2741 $keys[] = $index; 2742 } 2743 } 2744 return $keys; 2745 } 2746 2747 /** 2748 * Returns HTML for a fieldset form element and its children. 2749 * 2750 * @param $variables 2751 * An associative array containing: 2752 * - element: An associative array containing the properties of the element. 2753 * Properties used: #attributes, #children, #collapsed, #collapsible, 2754 * #description, #id, #title, #value. 2755 * 2756 * @ingroup themeable 2757 */ 2758 function theme_fieldset($variables) { 2759 $element = $variables['element']; 2760 element_set_attributes($element, array('id')); 2761 _form_set_class($element, array('form-wrapper')); 2762 2763 $output = '<fieldset' . drupal_attributes($element['#attributes']) . '>'; 2764 if (!empty($element['#title'])) { 2765 // Always wrap fieldset legends in a SPAN for CSS positioning. 2766 $output .= '<legend><span class="fieldset-legend">' . $element['#title'] . '</span></legend>'; 2767 } 2768 $output .= '<div class="fieldset-wrapper">'; 2769 if (!empty($element['#description'])) { 2770 $output .= '<div class="fieldset-description">' . $element['#description'] . '</div>'; 2771 } 2772 $output .= $element['#children']; 2773 if (isset($element['#value'])) { 2774 $output .= $element['#value']; 2775 } 2776 $output .= '</div>'; 2777 $output .= "</fieldset>\n"; 2778 return $output; 2779 } 2780 2781 /** 2782 * Returns HTML for a radio button form element. 2783 * 2784 * Note: The input "name" attribute needs to be sanitized before output, which 2785 * is currently done by passing all attributes to drupal_attributes(). 2786 * 2787 * @param $variables 2788 * An associative array containing: 2789 * - element: An associative array containing the properties of the element. 2790 * Properties used: #required, #return_value, #value, #attributes, #title, 2791 * #description 2792 * 2793 * @ingroup themeable 2794 */ 2795 function theme_radio($variables) { 2796 $element = $variables['element']; 2797 $element['#attributes']['type'] = 'radio'; 2798 element_set_attributes($element, array('id', 'name', '#return_value' => 'value')); 2799 2800 if (isset($element['#return_value']) && $element['#value'] !== FALSE && $element['#value'] == $element['#return_value']) { 2801 $element['#attributes']['checked'] = 'checked'; 2802 } 2803 _form_set_class($element, array('form-radio')); 2804 2805 return '<input' . drupal_attributes($element['#attributes']) . ' />'; 2806 } 2807 2808 /** 2809 * Returns HTML for a set of radio button form elements. 2810 * 2811 * @param $variables 2812 * An associative array containing: 2813 * - element: An associative array containing the properties of the element. 2814 * Properties used: #title, #value, #options, #description, #required, 2815 * #attributes, #children. 2816 * 2817 * @ingroup themeable 2818 */ 2819 function theme_radios($variables) { 2820 $element = $variables['element']; 2821 $attributes = array(); 2822 if (isset($element['#id'])) { 2823 $attributes['id'] = $element['#id']; 2824 } 2825 $attributes['class'] = 'form-radios'; 2826 if (!empty($element['#attributes']['class'])) { 2827 $attributes['class'] .= ' ' . implode(' ', $element['#attributes']['class']); 2828 } 2829 if (isset($element['#attributes']['title'])) { 2830 $attributes['title'] = $element['#attributes']['title']; 2831 } 2832 return '<div' . drupal_attributes($attributes) . '>' . (!empty($element['#children']) ? $element['#children'] : '') . '</div>'; 2833 } 2834 2835 /** 2836 * Expand a password_confirm field into two text boxes. 2837 */ 2838 function form_process_password_confirm($element) { 2839 $element['pass1'] = array( 2840 '#type' => 'password', 2841 '#title' => t('Password'), 2842 '#value' => empty($element['#value']) ? NULL : $element['#value']['pass1'], 2843 '#required' => $element['#required'], 2844 '#attributes' => array('class' => array('password-field')), 2845 ); 2846 $element['pass2'] = array( 2847 '#type' => 'password', 2848 '#title' => t('Confirm password'), 2849 '#value' => empty($element['#value']) ? NULL : $element['#value']['pass2'], 2850 '#required' => $element['#required'], 2851 '#attributes' => array('class' => array('password-confirm')), 2852 ); 2853 $element['#element_validate'] = array('password_confirm_validate'); 2854 $element['#tree'] = TRUE; 2855 2856 if (isset($element['#size'])) { 2857 $element['pass1']['#size'] = $element['pass2']['#size'] = $element['#size']; 2858 } 2859 2860 return $element; 2861 } 2862 2863 /** 2864 * Validates a password_confirm element. 2865 */ 2866 function password_confirm_validate($element, &$element_state) { 2867 $pass1 = trim($element['pass1']['#value']); 2868 $pass2 = trim($element['pass2']['#value']); 2869 if (!empty($pass1) || !empty($pass2)) { 2870 if (strcmp($pass1, $pass2)) { 2871 form_error($element, t('The specified passwords do not match.')); 2872 } 2873 } 2874 elseif ($element['#required'] && !empty($element_state['input'])) { 2875 form_error($element, t('Password field is required.')); 2876 } 2877 2878 // Password field must be converted from a two-element array into a single 2879 // string regardless of validation results. 2880 form_set_value($element['pass1'], NULL, $element_state); 2881 form_set_value($element['pass2'], NULL, $element_state); 2882 form_set_value($element, $pass1, $element_state); 2883 2884 return $element; 2885 2886 } 2887 2888 /** 2889 * Returns HTML for a date selection form element. 2890 * 2891 * @param $variables 2892 * An associative array containing: 2893 * - element: An associative array containing the properties of the element. 2894 * Properties used: #title, #value, #options, #description, #required, 2895 * #attributes. 2896 * 2897 * @ingroup themeable 2898 */ 2899 function theme_date($variables) { 2900 $element = $variables['element']; 2901 2902 $attributes = array(); 2903 if (isset($element['#id'])) { 2904 $attributes['id'] = $element['#id']; 2905 } 2906 if (!empty($element['#attributes']['class'])) { 2907 $attributes['class'] = (array) $element['#attributes']['class']; 2908 } 2909 $attributes['class'][] = 'container-inline'; 2910 2911 return '<div' . drupal_attributes($attributes) . '>' . drupal_render_children($element) . '</div>'; 2912 } 2913 2914 /** 2915 * Expands a date element into year, month, and day select elements. 2916 */ 2917 function form_process_date($element) { 2918 // Default to current date 2919 if (empty($element['#value'])) { 2920 $element['#value'] = array( 2921 'day' => format_date(REQUEST_TIME, 'custom', 'j'), 2922 'month' => format_date(REQUEST_TIME, 'custom', 'n'), 2923 'year' => format_date(REQUEST_TIME, 'custom', 'Y'), 2924 ); 2925 } 2926 2927 $element['#tree'] = TRUE; 2928 2929 // Determine the order of day, month, year in the site's chosen date format. 2930 $format = variable_get('date_format_short', 'm/d/Y - H:i'); 2931 $sort = array(); 2932 $sort['day'] = max(strpos($format, 'd'), strpos($format, 'j')); 2933 $sort['month'] = max(strpos($format, 'm'), strpos($format, 'M')); 2934 $sort['year'] = strpos($format, 'Y'); 2935 asort($sort); 2936 $order = array_keys($sort); 2937 2938 // Output multi-selector for date. 2939 foreach ($order as $type) { 2940 switch ($type) { 2941 case 'day': 2942 $options = drupal_map_assoc(range(1, 31)); 2943 $title = t('Day'); 2944 break; 2945 2946 case 'month': 2947 $options = drupal_map_assoc(range(1, 12), 'map_month'); 2948 $title = t('Month'); 2949 break; 2950 2951 case 'year': 2952 $options = drupal_map_assoc(range(1900, 2050)); 2953 $title = t('Year'); 2954 break; 2955 } 2956 2957 $element[$type] = array( 2958 '#type' => 'select', 2959 '#title' => $title, 2960 '#title_display' => 'invisible', 2961 '#value' => $element['#value'][$type], 2962 '#attributes' => $element['#attributes'], 2963 '#options' => $options, 2964 ); 2965 } 2966 2967 return $element; 2968 } 2969 2970 /** 2971 * Validates the date type to prevent invalid dates (e.g., February 30, 2006). 2972 */ 2973 function date_validate($element) { 2974 if (!checkdate($element['#value']['month'], $element['#value']['day'], $element['#value']['year'])) { 2975 form_error($element, t('The specified date is invalid.')); 2976 } 2977 } 2978 2979 /** 2980 * Helper function for usage with drupal_map_assoc to display month names. 2981 */ 2982 function map_month($month) { 2983 $months = &drupal_static(__FUNCTION__, array( 2984 1 => 'Jan', 2985 2 => 'Feb', 2986 3 => 'Mar', 2987 4 => 'Apr', 2988 5 => 'May', 2989 6 => 'Jun', 2990 7 => 'Jul', 2991 8 => 'Aug', 2992 9 => 'Sep', 2993 10 => 'Oct', 2994 11 => 'Nov', 2995 12 => 'Dec', 2996 )); 2997 return t($months[$month]); 2998 } 2999 3000 /** 3001 * Sets the value for a weight element, with zero as a default. 3002 */ 3003 function weight_value(&$form) { 3004 if (isset($form['#default_value'])) { 3005 $form['#value'] = $form['#default_value']; 3006 } 3007 else { 3008 $form['#value'] = 0; 3009 } 3010 } 3011 3012 /** 3013 * Expands a radios element into individual radio elements. 3014 */ 3015 function form_process_radios($element) { 3016 if (count($element['#options']) > 0) { 3017 $weight = 0; 3018 foreach ($element['#options'] as $key => $choice) { 3019 // Maintain order of options as defined in #options, in case the element 3020 // defines custom option sub-elements, but does not define all option 3021 // sub-elements. 3022 $weight += 0.001; 3023 3024 $element += array($key => array()); 3025 // Generate the parents as the autogenerator does, so we will have a 3026 // unique id for each radio button. 3027 $parents_for_id = array_merge($element['#parents'], array($key)); 3028 $element[$key] += array( 3029 '#type' => 'radio', 3030 '#title' => $choice, 3031 // The key is sanitized in drupal_attributes() during output from the 3032 // theme function. 3033 '#return_value' => $key, 3034 // Use default or FALSE. A value of FALSE means that the radio button is 3035 // not 'checked'. 3036 '#default_value' => isset($element['#default_value']) ? $element['#default_value'] : FALSE, 3037 '#attributes' => $element['#attributes'], 3038 '#parents' => $element['#parents'], 3039 '#id' => drupal_html_id('edit-' . implode('-', $parents_for_id)), 3040 '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL, 3041 '#weight' => $weight, 3042 ); 3043 } 3044 } 3045 return $element; 3046 } 3047 3048 /** 3049 * Returns HTML for a checkbox form element. 3050 * 3051 * @param $variables 3052 * An associative array containing: 3053 * - element: An associative array containing the properties of the element. 3054 * Properties used: #title, #value, #return_value, #description, #required, 3055 * #attributes, #checked. 3056 * 3057 * @ingroup themeable 3058 */ 3059 function theme_checkbox($variables) { 3060 $element = $variables['element']; 3061 $t = get_t(); 3062 $element['#attributes']['type'] = 'checkbox'; 3063 element_set_attributes($element, array('id', 'name', '#return_value' => 'value')); 3064 3065 // Unchecked checkbox has #value of integer 0. 3066 if (!empty($element['#checked'])) { 3067 $element['#attributes']['checked'] = 'checked'; 3068 } 3069 _form_set_class($element, array('form-checkbox')); 3070 3071 return '<input' . drupal_attributes($element['#attributes']) . ' />'; 3072 } 3073 3074 /** 3075 * Returns HTML for a set of checkbox form elements. 3076 * 3077 * @param $variables 3078 * An associative array containing: 3079 * - element: An associative array containing the properties of the element. 3080 * Properties used: #children, #attributes. 3081 * 3082 * @ingroup themeable 3083 */ 3084 function theme_checkboxes($variables) { 3085 $element = $variables['element']; 3086 $attributes = array(); 3087 if (isset($element['#id'])) { 3088 $attributes['id'] = $element['#id']; 3089 } 3090 $attributes['class'][] = 'form-checkboxes'; 3091 if (!empty($element['#attributes']['class'])) { 3092 $attributes['class'] = array_merge($attributes['class'], $element['#attributes']['class']); 3093 } 3094 if (isset($element['#attributes']['title'])) { 3095 $attributes['title'] = $element['#attributes']['title']; 3096 } 3097 return '<div' . drupal_attributes($attributes) . '>' . (!empty($element['#children']) ? $element['#children'] : '') . '</div>'; 3098 } 3099 3100 /** 3101 * Adds form element theming to an element if its title or description is set. 3102 * 3103 * This is used as a pre render function for checkboxes and radios. 3104 */ 3105 function form_pre_render_conditional_form_element($element) { 3106 $t = get_t(); 3107 // Set the element's title attribute to show #title as a tooltip, if needed. 3108 if (isset($element['#title']) && $element['#title_display'] == 'attribute') { 3109 $element['#attributes']['title'] = $element['#title']; 3110 if (!empty($element['#required'])) { 3111 // Append an indication that this field is required. 3112 $element['#attributes']['title'] .= ' (' . $t('Required') . ')'; 3113 } 3114 } 3115 3116 if (isset($element['#title']) || isset($element['#description'])) { 3117 $element['#theme_wrappers'][] = 'form_element'; 3118 } 3119 return $element; 3120 } 3121 3122 /** 3123 * Sets the #checked property of a checkbox element. 3124 */ 3125 function form_process_checkbox($element, $form_state) { 3126 $value = $element['#value']; 3127 $return_value = $element['#return_value']; 3128 // On form submission, the #value of an available and enabled checked 3129 // checkbox is #return_value, and the #value of an available and enabled 3130 // unchecked checkbox is integer 0. On not submitted forms, and for 3131 // checkboxes with #access=FALSE or #disabled=TRUE, the #value is 3132 // #default_value (integer 0 if #default_value is NULL). Most of the time, 3133 // a string comparison of #value and #return_value is sufficient for 3134 // determining the "checked" state, but a value of TRUE always means checked 3135 // (even if #return_value is 'foo'), and a value of FALSE or integer 0 always 3136 // means unchecked (even if #return_value is '' or '0'). 3137 if ($value === TRUE || $value === FALSE || $value === 0) { 3138 $element['#checked'] = (bool) $value; 3139 } 3140 else { 3141 // Compare as strings, so that 15 is not considered equal to '15foo', but 1 3142 // is considered equal to '1'. This cast does not imply that either #value 3143 // or #return_value is expected to be a string. 3144 $element['#checked'] = ((string) $value === (string) $return_value); 3145 } 3146 return $element; 3147 } 3148 3149 /** 3150 * Processes a checkboxes form element. 3151 */ 3152 function form_process_checkboxes($element) { 3153 $value = is_array($element['#value']) ? $element['#value'] : array(); 3154 $element['#tree'] = TRUE; 3155 if (count($element['#options']) > 0) { 3156 if (!isset($element['#default_value']) || $element['#default_value'] == 0) { 3157 $element['#default_value'] = array(); 3158 } 3159 $weight = 0; 3160 foreach ($element['#options'] as $key => $choice) { 3161 // Integer 0 is not a valid #return_value, so use '0' instead. 3162 // @see form_type_checkbox_value(). 3163 // @todo For Drupal 8, cast all integer keys to strings for consistency 3164 // with form_process_radios(). 3165 if ($key === 0) { 3166 $key = '0'; 3167 } 3168 // Maintain order of options as defined in #options, in case the element 3169 // defines custom option sub-elements, but does not define all option 3170 // sub-elements. 3171 $weight += 0.001; 3172 3173 $element += array($key => array()); 3174 $element[$key] += array( 3175 '#type' => 'checkbox', 3176 '#title' => $choice, 3177 '#return_value' => $key, 3178 '#default_value' => isset($value[$key]) ? $key : NULL, 3179 '#attributes' => $element['#attributes'], 3180 '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL, 3181 '#weight' => $weight, 3182 ); 3183 } 3184 } 3185 return $element; 3186 } 3187 3188 /** 3189 * Processes a form actions container element. 3190 * 3191 * @param $element 3192 * An associative array containing the properties and children of the 3193 * form actions container. 3194 * @param $form_state 3195 * The $form_state array for the form this element belongs to. 3196 * 3197 * @return 3198 * The processed element. 3199 */ 3200 function form_process_actions($element, &$form_state) { 3201 $element['#attributes']['class'][] = 'form-actions'; 3202 return $element; 3203 } 3204 3205 /** 3206 * Processes a container element. 3207 * 3208 * @param $element 3209 * An associative array containing the properties and children of the 3210 * container. 3211 * @param $form_state 3212 * The $form_state array for the form this element belongs to. 3213 * 3214 * @return 3215 * The processed element. 3216 */ 3217 function form_process_container($element, &$form_state) { 3218 // Generate the ID of the element if it's not explicitly given. 3219 if (!isset($element['#id'])) { 3220 $element['#id'] = drupal_html_id(implode('-', $element['#parents']) . '-wrapper'); 3221 } 3222 return $element; 3223 } 3224 3225 /** 3226 * Returns HTML to wrap child elements in a container. 3227 * 3228 * Used for grouped form items. Can also be used as a #theme_wrapper for any 3229 * renderable element, to surround it with a <div> and add attributes such as 3230 * classes or an HTML id. 3231 * 3232 * @param $variables 3233 * An associative array containing: 3234 * - element: An associative array containing the properties of the element. 3235 * Properties used: #id, #attributes, #children. 3236 * 3237 * @ingroup themeable 3238 */ 3239 function theme_container($variables) { 3240 $element = $variables['element']; 3241 3242 // Special handling for form elements. 3243 if (isset($element['#array_parents'])) { 3244 // Assign an html ID. 3245 if (!isset($element['#attributes']['id'])) { 3246 $element['#attributes']['id'] = $element['#id']; 3247 } 3248 // Add the 'form-wrapper' class. 3249 $element['#attributes']['class'][] = 'form-wrapper'; 3250 } 3251 3252 return '<div' . drupal_attributes($element['#attributes']) . '>' . $element['#children'] . '</div>'; 3253 } 3254 3255 /** 3256 * Returns HTML for a table with radio buttons or checkboxes. 3257 * 3258 * @param $variables 3259 * An associative array containing: 3260 * - element: An associative array containing the properties and children of 3261 * the tableselect element. Properties used: #header, #options, #empty, 3262 * and #js_select. The #options property is an array of selection options; 3263 * each array element of #options is an array of properties. These 3264 * properties can include #attributes, which is added to the 3265 * table row's HTML attributes; see theme_table(). An example of per-row 3266 * options: 3267 * @code 3268 * $options = array( 3269 * array( 3270 * 'title' => 'How to Learn Drupal', 3271 * 'content_type' => 'Article', 3272 * 'status' => 'published', 3273 * '#attributes' => array('class' => array('article-row')), 3274 * ), 3275 * array( 3276 * 'title' => 'Privacy Policy', 3277 * 'content_type' => 'Page', 3278 * 'status' => 'published', 3279 * '#attributes' => array('class' => array('page-row')), 3280 * ), 3281 * ); 3282 * $header = array( 3283 * 'title' => t('Title'), 3284 * 'content_type' => t('Content type'), 3285 * 'status' => t('Status'), 3286 * ); 3287 * $form['table'] = array( 3288 * '#type' => 'tableselect', 3289 * '#header' => $header, 3290 * '#options' => $options, 3291 * '#empty' => t('No content available.'), 3292 * ); 3293 * @endcode 3294 * 3295 * @ingroup themeable 3296 */ 3297 function theme_tableselect($variables) { 3298 $element = $variables['element']; 3299 $rows = array(); 3300 $header = $element['#header']; 3301 if (!empty($element['#options'])) { 3302 // Generate a table row for each selectable item in #options. 3303 foreach (element_children($element) as $key) { 3304 $row = array(); 3305 3306 $row['data'] = array(); 3307 if (isset($element['#options'][$key]['#attributes'])) { 3308 $row += $element['#options'][$key]['#attributes']; 3309 } 3310 // Render the checkbox / radio element. 3311 $row['data'][] = drupal_render($element[$key]); 3312 3313 // As theme_table only maps header and row columns by order, create the 3314 // correct order by iterating over the header fields. 3315 foreach ($element['#header'] as $fieldname => $title) { 3316 $row['data'][] = $element['#options'][$key][$fieldname]; 3317 } 3318 $rows[] = $row; 3319 } 3320 // Add an empty header or a "Select all" checkbox to provide room for the 3321 // checkboxes/radios in the first table column. 3322 if ($element['#js_select']) { 3323 // Add a "Select all" checkbox. 3324 drupal_add_js('misc/tableselect.js'); 3325 array_unshift($header, array('class' => array('select-all'))); 3326 } 3327 else { 3328 // Add an empty header when radio buttons are displayed or a "Select all" 3329 // checkbox is not desired. 3330 array_unshift($header, ''); 3331 } 3332 } 3333 return theme('table', array('header' => $header, 'rows' => $rows, 'empty' => $element['#empty'], 'attributes' => $element['#attributes'])); 3334 } 3335 3336 /** 3337 * Creates checkbox or radio elements to populate a tableselect table. 3338 * 3339 * @param $element 3340 * An associative array containing the properties and children of the 3341 * tableselect element. 3342 * 3343 * @return 3344 * The processed element. 3345 */ 3346 function form_process_tableselect($element) { 3347 3348 if ($element['#multiple']) { 3349 $value = is_array($element['#value']) ? $element['#value'] : array(); 3350 } 3351 else { 3352 // Advanced selection behavior makes no sense for radios. 3353 $element['#js_select'] = FALSE; 3354 } 3355 3356 $element['#tree'] = TRUE; 3357 3358 if (count($element['#options']) > 0) { 3359 if (!isset($element['#default_value']) || $element['#default_value'] === 0) { 3360 $element['#default_value'] = array(); 3361 } 3362 3363 // Create a checkbox or radio for each item in #options in such a way that 3364 // the value of the tableselect element behaves as if it had been of type 3365 // checkboxes or radios. 3366 foreach ($element['#options'] as $key => $choice) { 3367 // Do not overwrite manually created children. 3368 if (!isset($element[$key])) { 3369 if ($element['#multiple']) { 3370 $title = ''; 3371 if (!empty($element['#options'][$key]['title']['data']['#title'])) { 3372 $title = t('Update @title', array( 3373 '@title' => $element['#options'][$key]['title']['data']['#title'], 3374 )); 3375 } 3376 $element[$key] = array( 3377 '#type' => 'checkbox', 3378 '#title' => $title, 3379 '#title_display' => 'invisible', 3380 '#return_value' => $key, 3381 '#default_value' => isset($value[$key]) ? $key : NULL, 3382 '#attributes' => $element['#attributes'], 3383 ); 3384 } 3385 else { 3386 // Generate the parents as the autogenerator does, so we will have a 3387 // unique id for each radio button. 3388 $parents_for_id = array_merge($element['#parents'], array($key)); 3389 $element[$key] = array( 3390 '#type' => 'radio', 3391 '#title' => '', 3392 '#return_value' => $key, 3393 '#default_value' => ($element['#default_value'] == $key) ? $key : NULL, 3394 '#attributes' => $element['#attributes'], 3395 '#parents' => $element['#parents'], 3396 '#id' => drupal_html_id('edit-' . implode('-', $parents_for_id)), 3397 '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL, 3398 ); 3399 } 3400 if (isset($element['#options'][$key]['#weight'])) { 3401 $element[$key]['#weight'] = $element['#options'][$key]['#weight']; 3402 } 3403 } 3404 } 3405 } 3406 else { 3407 $element['#value'] = array(); 3408 } 3409 return $element; 3410 } 3411 3412 /** 3413 * Processes a machine-readable name form element. 3414 * 3415 * @param $element 3416 * The form element to process. Properties used: 3417 * - #machine_name: An associative array containing: 3418 * - exists: A function name to invoke for checking whether a submitted 3419 * machine name value already exists. The submitted value is passed as 3420 * argument. In most cases, an existing API or menu argument loader 3421 * function can be re-used. The callback is only invoked, if the submitted 3422 * value differs from the element's #default_value. 3423 * - source: (optional) The #array_parents of the form element containing 3424 * the human-readable name (i.e., as contained in the $form structure) to 3425 * use as source for the machine name. Defaults to array('name'). 3426 * - label: (optional) A text to display as label for the machine name value 3427 * after the human-readable name form element. Defaults to "Machine name". 3428 * - replace_pattern: (optional) A regular expression (without delimiters) 3429 * matching disallowed characters in the machine name. Defaults to 3430 * '[^a-z0-9_]+'. 3431 * - replace: (optional) A character to replace disallowed characters in the 3432 * machine name via JavaScript. Defaults to '_' (underscore). When using a 3433 * different character, 'replace_pattern' needs to be set accordingly. 3434 * - error: (optional) A custom form error message string to show, if the 3435 * machine name contains disallowed characters. 3436 * - standalone: (optional) Whether the live preview should stay in its own 3437 * form element rather than in the suffix of the source element. Defaults 3438 * to FALSE. 3439 * - #maxlength: (optional) Should be set to the maximum allowed length of the 3440 * machine name. Defaults to 64. 3441 * - #disabled: (optional) Should be set to TRUE in case an existing machine 3442 * name must not be changed after initial creation. 3443 */ 3444 function form_process_machine_name($element, &$form_state) { 3445 // Apply default form element properties. 3446 $element += array( 3447 '#title' => t('Machine-readable name'), 3448 '#description' => t('A unique machine-readable name. Can only contain lowercase letters, numbers, and underscores.'), 3449 '#machine_name' => array(), 3450 '#field_prefix' => '', 3451 '#field_suffix' => '', 3452 '#suffix' => '', 3453 ); 3454 // A form element that only wants to set one #machine_name property (usually 3455 // 'source' only) would leave all other properties undefined, if the defaults 3456 // were defined in hook_element_info(). Therefore, we apply the defaults here. 3457 $element['#machine_name'] += array( 3458 'source' => array('name'), 3459 'target' => '#' . $element['#id'], 3460 'label' => t('Machine name'), 3461 'replace_pattern' => '[^a-z0-9_]+', 3462 'replace' => '_', 3463 'standalone' => FALSE, 3464 'field_prefix' => $element['#field_prefix'], 3465 'field_suffix' => $element['#field_suffix'], 3466 ); 3467 3468 // By default, machine names are restricted to Latin alphanumeric characters. 3469 // So, default to LTR directionality. 3470 if (!isset($element['#attributes'])) { 3471 $element['#attributes'] = array(); 3472 } 3473 $element['#attributes'] += array('dir' => 'ltr'); 3474 3475 // The source element defaults to array('name'), but may have been overidden. 3476 if (empty($element['#machine_name']['source'])) { 3477 return $element; 3478 } 3479 3480 // Retrieve the form element containing the human-readable name from the 3481 // complete form in $form_state. By reference, because we may need to append 3482 // a #field_suffix that will hold the live preview. 3483 $key_exists = NULL; 3484 $source = drupal_array_get_nested_value($form_state['complete form'], $element['#machine_name']['source'], $key_exists); 3485 if (!$key_exists) { 3486 return $element; 3487 } 3488 3489 $suffix_id = $source['#id'] . '-machine-name-suffix'; 3490 $element['#machine_name']['suffix'] = '#' . $suffix_id; 3491 3492 if ($element['#machine_name']['standalone']) { 3493 $element['#suffix'] .= ' <small id="' . $suffix_id . '"> </small>'; 3494 } 3495 else { 3496 // Append a field suffix to the source form element, which will contain 3497 // the live preview of the machine name. 3498 $source += array('#field_suffix' => ''); 3499 $source['#field_suffix'] .= ' <small id="' . $suffix_id . '"> </small>'; 3500 3501 $parents = array_merge($element['#machine_name']['source'], array('#field_suffix')); 3502 drupal_array_set_nested_value($form_state['complete form'], $parents, $source['#field_suffix']); 3503 } 3504 3505 $js_settings = array( 3506 'type' => 'setting', 3507 'data' => array( 3508 'machineName' => array( 3509 '#' . $source['#id'] => $element['#machine_name'], 3510 ), 3511 ), 3512 ); 3513 $element['#attached']['js'][] = 'misc/machine-name.js'; 3514 $element['#attached']['js'][] = $js_settings; 3515 3516 return $element; 3517 } 3518 3519 /** 3520 * Form element validation handler for machine_name elements. 3521 * 3522 * Note that #maxlength is validated by _form_validate() already. 3523 */ 3524 function form_validate_machine_name(&$element, &$form_state) { 3525 // Verify that the machine name not only consists of replacement tokens. 3526 if (preg_match('@^' . $element['#machine_name']['replace'] . '+$@', $element['#value'])) { 3527 form_error($element, t('The machine-readable name must contain unique characters.')); 3528 } 3529 3530 // Verify that the machine name contains no disallowed characters. 3531 if (preg_match('@' . $element['#machine_name']['replace_pattern'] . '@', $element['#value'])) { 3532 if (!isset($element['#machine_name']['error'])) { 3533 // Since a hyphen is the most common alternative replacement character, 3534 // a corresponding validation error message is supported here. 3535 if ($element['#machine_name']['replace'] == '-') { 3536 form_error($element, t('The machine-readable name must contain only lowercase letters, numbers, and hyphens.')); 3537 } 3538 // Otherwise, we assume the default (underscore). 3539 else { 3540 form_error($element, t('The machine-readable name must contain only lowercase letters, numbers, and underscores.')); 3541 } 3542 } 3543 else { 3544 form_error($element, $element['#machine_name']['error']); 3545 } 3546 } 3547 3548 // Verify that the machine name is unique. 3549 if ($element['#default_value'] !== $element['#value']) { 3550 $function = $element['#machine_name']['exists']; 3551 if ($function($element['#value'], $element, $form_state)) { 3552 form_error($element, t('The machine-readable name is already in use. It must be unique.')); 3553 } 3554 } 3555 } 3556 3557 /** 3558 * Arranges fieldsets into groups. 3559 * 3560 * @param $element 3561 * An associative array containing the properties and children of the 3562 * fieldset. Note that $element must be taken by reference here, so processed 3563 * child elements are taken over into $form_state. 3564 * @param $form_state 3565 * The $form_state array for the form this fieldset belongs to. 3566 * 3567 * @return 3568 * The processed element. 3569 */ 3570 function form_process_fieldset(&$element, &$form_state) { 3571 $parents = implode('][', $element['#parents']); 3572 3573 // Each fieldset forms a new group. The #type 'vertical_tabs' basically only 3574 // injects a new fieldset. 3575 $form_state['groups'][$parents]['#group_exists'] = TRUE; 3576 $element['#groups'] = &$form_state['groups']; 3577 3578 // Process vertical tabs group member fieldsets. 3579 if (isset($element['#group'])) { 3580 // Add this fieldset to the defined group (by reference). 3581 $group = $element['#group']; 3582 $form_state['groups'][$group][] = &$element; 3583 } 3584 3585 // Contains form element summary functionalities. 3586 $element['#attached']['library'][] = array('system', 'drupal.form'); 3587 3588 // The .form-wrapper class is required for #states to treat fieldsets like 3589 // containers. 3590 if (!isset($element['#attributes']['class'])) { 3591 $element['#attributes']['class'] = array(); 3592 } 3593 3594 // Collapsible fieldsets 3595 if (!empty($element['#collapsible'])) { 3596 $element['#attached']['library'][] = array('system', 'drupal.collapse'); 3597 $element['#attributes']['class'][] = 'collapsible'; 3598 if (!empty($element['#collapsed'])) { 3599 $element['#attributes']['class'][] = 'collapsed'; 3600 } 3601 } 3602 3603 return $element; 3604 } 3605 3606 /** 3607 * Adds members of this group as actual elements for rendering. 3608 * 3609 * @param $element 3610 * An associative array containing the properties and children of the 3611 * fieldset. 3612 * 3613 * @return 3614 * The modified element with all group members. 3615 */ 3616 function form_pre_render_fieldset($element) { 3617 // Fieldsets may be rendered outside of a Form API context. 3618 if (!isset($element['#parents']) || !isset($element['#groups'])) { 3619 return $element; 3620 } 3621 // Inject group member elements belonging to this group. 3622 $parents = implode('][', $element['#parents']); 3623 $children = element_children($element['#groups'][$parents]); 3624 if (!empty($children)) { 3625 foreach ($children as $key) { 3626 // Break references and indicate that the element should be rendered as 3627 // group member. 3628 $child = (array) $element['#groups'][$parents][$key]; 3629 $child['#group_fieldset'] = TRUE; 3630 // Inject the element as new child element. 3631 $element[] = $child; 3632 3633 $sort = TRUE; 3634 } 3635 // Re-sort the element's children if we injected group member elements. 3636 if (isset($sort)) { 3637 $element['#sorted'] = FALSE; 3638 } 3639 } 3640 3641 if (isset($element['#group'])) { 3642 $group = $element['#group']; 3643 // If this element belongs to a group, but the group-holding element does 3644 // not exist, we need to render it (at its original location). 3645 if (!isset($element['#groups'][$group]['#group_exists'])) { 3646 // Intentionally empty to clarify the flow; we simply return $element. 3647 } 3648 // If we injected this element into the group, then we want to render it. 3649 elseif (!empty($element['#group_fieldset'])) { 3650 // Intentionally empty to clarify the flow; we simply return $element. 3651 } 3652 // Otherwise, this element belongs to a group and the group exists, so we do 3653 // not render it. 3654 elseif (element_children($element['#groups'][$group])) { 3655 $element['#printed'] = TRUE; 3656 } 3657 } 3658 3659 return $element; 3660 } 3661 3662 /** 3663 * Creates a group formatted as vertical tabs. 3664 * 3665 * Note that autocomplete callbacks should include special handling as the 3666 * user's input may contain forward slashes. If the user-submitted string has a 3667 * '/' in the text that is sent in the autocomplete request, the menu system 3668 * will split the text and pass it to the callback as multiple arguments. 3669 * 3670 * Suppose your autocomplete path in the menu system is 'mymodule_autocomplete.' 3671 * In your form you have: 3672 * @code 3673 * '#autocomplete_path' => 'mymodule_autocomplete/' . $some_key . '/' . $some_id, 3674 * @endcode 3675 * The user types in "keywords" so the full path called is: 3676 * 'mymodule_autocomplete/$some_key/$some_id/keywords' 3677 * 3678 * You should include code similar to the following to handle slashes in the 3679 * input: 3680 * @code 3681 * function mymodule_autocomplete_callback($arg1, $arg2, $keywords) { 3682 * $args = func_get_args(); 3683 * // We need to remove $arg1 and $arg2 from the beginning of the array so we 3684 * // are left with the keywords. 3685 * array_shift($args); 3686 * array_shift($args); 3687 * // We store the user's original input in $keywords, including any slashes. 3688 * $keywords = implode('/', $args); 3689 * 3690 * // Your code here. 3691 * } 3692 * @endcode 3693 * 3694 * @param $element 3695 * An associative array containing the properties and children of the 3696 * fieldset. 3697 * @param $form_state 3698 * The $form_state array for the form this vertical tab widget belongs to. 3699 * 3700 * @return 3701 * The processed element. 3702 */ 3703 function form_process_vertical_tabs($element, &$form_state) { 3704 // Inject a new fieldset as child, so that form_process_fieldset() processes 3705 // this fieldset like any other fieldset. 3706 $element['group'] = array( 3707 '#type' => 'fieldset', 3708 '#theme_wrappers' => array(), 3709 '#parents' => $element['#parents'], 3710 ); 3711 3712 // The JavaScript stores the currently selected tab in this hidden 3713 // field so that the active tab can be restored the next time the 3714 // form is rendered, e.g. on preview pages or when form validation 3715 // fails. 3716 $name = implode('__', $element['#parents']); 3717 if (isset($form_state['values'][$name . '__active_tab'])) { 3718 $element['#default_tab'] = $form_state['values'][$name . '__active_tab']; 3719 } 3720 $element[$name . '__active_tab'] = array( 3721 '#type' => 'hidden', 3722 '#default_value' => $element['#default_tab'], 3723 '#attributes' => array('class' => array('vertical-tabs-active-tab')), 3724 ); 3725 3726 return $element; 3727 } 3728 3729 /** 3730 * Returns HTML for an element's children fieldsets as vertical tabs. 3731 * 3732 * @param $variables 3733 * An associative array containing: 3734 * - element: An associative array containing the properties and children of 3735 * the fieldset. Properties used: #children. 3736 * 3737 * @ingroup themeable 3738 */ 3739 function theme_vertical_tabs($variables) { 3740 $element = $variables['element']; 3741 // Add required JavaScript and Stylesheet. 3742 drupal_add_library('system', 'drupal.vertical-tabs'); 3743 3744 $output = '<h2 class="element-invisible">' . t('Vertical Tabs') . '</h2>'; 3745 $output .= '<div class="vertical-tabs-panes">' . $element['#children'] . '</div>'; 3746 return $output; 3747 } 3748 3749 /** 3750 * Returns HTML for a submit button form element. 3751 * 3752 * @param $variables 3753 * An associative array containing: 3754 * - element: An associative array containing the properties of the element. 3755 * Properties used: #attributes, #button_type, #name, #value. 3756 * 3757 * @ingroup themeable 3758 */ 3759 function theme_submit($variables) { 3760 return theme('button', $variables['element']); 3761 } 3762 3763 /** 3764 * Returns HTML for a button form element. 3765 * 3766 * @param $variables 3767 * An associative array containing: 3768 * - element: An associative array containing the properties of the element. 3769 * Properties used: #attributes, #button_type, #name, #value. 3770 * 3771 * @ingroup themeable 3772 */ 3773 function theme_button($variables) { 3774 $element = $variables['element']; 3775 $element['#attributes']['type'] = 'submit'; 3776 element_set_attributes($element, array('id', 'name', 'value')); 3777 3778 $element['#attributes']['class'][] = 'form-' . $element['#button_type']; 3779 if (!empty($element['#attributes']['disabled'])) { 3780 $element['#attributes']['class'][] = 'form-button-disabled'; 3781 } 3782 3783 return '<input' . drupal_attributes($element['#attributes']) . ' />'; 3784 } 3785 3786 /** 3787 * Returns HTML for an image button form element. 3788 * 3789 * @param $variables 3790 * An associative array containing: 3791 * - element: An associative array containing the properties of the element. 3792 * Properties used: #attributes, #button_type, #name, #value, #title, #src. 3793 * 3794 * @ingroup themeable 3795 */ 3796 function theme_image_button($variables) { 3797 $element = $variables['element']; 3798 $element['#attributes']['type'] = 'image'; 3799 element_set_attributes($element, array('id', 'name', 'value')); 3800 3801 $element['#attributes']['src'] = file_create_url($element['#src']); 3802 if (!empty($element['#title'])) { 3803 $element['#attributes']['alt'] = $element['#title']; 3804 $element['#attributes']['title'] = $element['#title']; 3805 } 3806 3807 $element['#attributes']['class'][] = 'form-' . $element['#button_type']; 3808 if (!empty($element['#attributes']['disabled'])) { 3809 $element['#attributes']['class'][] = 'form-button-disabled'; 3810 } 3811 3812 return '<input' . drupal_attributes($element['#attributes']) . ' />'; 3813 } 3814 3815 /** 3816 * Returns HTML for a hidden form element. 3817 * 3818 * @param $variables 3819 * An associative array containing: 3820 * - element: An associative array containing the properties of the element. 3821 * Properties used: #name, #value, #attributes. 3822 * 3823 * @ingroup themeable 3824 */ 3825 function theme_hidden($variables) { 3826 $element = $variables['element']; 3827 $element['#attributes']['type'] = 'hidden'; 3828 element_set_attributes($element, array('name', 'value')); 3829 return '<input' . drupal_attributes($element['#attributes']) . " />\n"; 3830 } 3831 3832 /** 3833 * Returns HTML for a textfield form element. 3834 * 3835 * @param $variables 3836 * An associative array containing: 3837 * - element: An associative array containing the properties of the element. 3838 * Properties used: #title, #value, #description, #size, #maxlength, 3839 * #required, #attributes, #autocomplete_path. 3840 * 3841 * @ingroup themeable 3842 */ 3843 function theme_textfield($variables) { 3844 $element = $variables['element']; 3845 $element['#attributes']['type'] = 'text'; 3846 element_set_attributes($element, array('id', 'name', 'value', 'size', 'maxlength')); 3847 _form_set_class($element, array('form-text')); 3848 3849 $extra = ''; 3850 if ($element['#autocomplete_path'] && drupal_valid_path($element['#autocomplete_path'])) { 3851 drupal_add_library('system', 'drupal.autocomplete'); 3852 $element['#attributes']['class'][] = 'form-autocomplete'; 3853 3854 $attributes = array(); 3855 $attributes['type'] = 'hidden'; 3856 $attributes['id'] = $element['#attributes']['id'] . '-autocomplete'; 3857 $attributes['value'] = url($element['#autocomplete_path'], array('absolute' => TRUE)); 3858 $attributes['disabled'] = 'disabled'; 3859 $attributes['class'][] = 'autocomplete'; 3860 $extra = '<input' . drupal_attributes($attributes) . ' />'; 3861 } 3862 3863 $output = '<input' . drupal_attributes($element['#attributes']) . ' />'; 3864 3865 return $output . $extra; 3866 } 3867 3868 /** 3869 * Returns HTML for a form. 3870 * 3871 * @param $variables 3872 * An associative array containing: 3873 * - element: An associative array containing the properties of the element. 3874 * Properties used: #action, #method, #attributes, #children 3875 * 3876 * @ingroup themeable 3877 */ 3878 function theme_form($variables) { 3879 $element = $variables['element']; 3880 if (isset($element['#action'])) { 3881 $element['#attributes']['action'] = drupal_strip_dangerous_protocols($element['#action']); 3882 } 3883 element_set_attributes($element, array('method', 'id')); 3884 if (empty($element['#attributes']['accept-charset'])) { 3885 $element['#attributes']['accept-charset'] = "UTF-8"; 3886 } 3887 // Anonymous DIV to satisfy XHTML compliance. 3888 return '<form' . drupal_attributes($element['#attributes']) . '><div>' . $element['#children'] . '</div></form>'; 3889 } 3890 3891 /** 3892 * Returns HTML for a textarea form element. 3893 * 3894 * @param $variables 3895 * An associative array containing: 3896 * - element: An associative array containing the properties of the element. 3897 * Properties used: #title, #value, #description, #rows, #cols, #required, 3898 * #attributes 3899 * 3900 * @ingroup themeable 3901 */ 3902 function theme_textarea($variables) { 3903 $element = $variables['element']; 3904 element_set_attributes($element, array('id', 'name', 'cols', 'rows')); 3905 _form_set_class($element, array('form-textarea')); 3906 3907 $wrapper_attributes = array( 3908 'class' => array('form-textarea-wrapper'), 3909 ); 3910 3911 // Add resizable behavior. 3912 if (!empty($element['#resizable'])) { 3913 drupal_add_library('system', 'drupal.textarea'); 3914 $wrapper_attributes['class'][] = 'resizable'; 3915 } 3916 3917 $output = '<div' . drupal_attributes($wrapper_attributes) . '>'; 3918 $output .= '<textarea' . drupal_attributes($element['#attributes']) . '>' . check_plain($element['#value']) . '</textarea>'; 3919 $output .= '</div>'; 3920 return $output; 3921 } 3922 3923 /** 3924 * Returns HTML for a password form element. 3925 * 3926 * @param $variables 3927 * An associative array containing: 3928 * - element: An associative array containing the properties of the element. 3929 * Properties used: #title, #value, #description, #size, #maxlength, 3930 * #required, #attributes. 3931 * 3932 * @ingroup themeable 3933 */ 3934 function theme_password($variables) { 3935 $element = $variables['element']; 3936 $element['#attributes']['type'] = 'password'; 3937 element_set_attributes($element, array('id', 'name', 'size', 'maxlength')); 3938 _form_set_class($element, array('form-text')); 3939 3940 return '<input' . drupal_attributes($element['#attributes']) . ' />'; 3941 } 3942 3943 /** 3944 * Expands a weight element into a select element. 3945 */ 3946 function form_process_weight($element) { 3947 $element['#is_weight'] = TRUE; 3948 3949 // If the number of options is small enough, use a select field. 3950 $max_elements = variable_get('drupal_weight_select_max', DRUPAL_WEIGHT_SELECT_MAX); 3951 if ($element['#delta'] <= $max_elements) { 3952 $element['#type'] = 'select'; 3953 for ($n = (-1 * $element['#delta']); $n <= $element['#delta']; $n++) { 3954 $weights[$n] = $n; 3955 } 3956 $element['#options'] = $weights; 3957 $element += element_info('select'); 3958 } 3959 // Otherwise, use a text field. 3960 else { 3961 $element['#type'] = 'textfield'; 3962 // Use a field big enough to fit most weights. 3963 $element['#size'] = 10; 3964 $element['#element_validate'] = array('element_validate_integer'); 3965 $element += element_info('textfield'); 3966 } 3967 3968 return $element; 3969 } 3970 3971 /** 3972 * Returns HTML for a file upload form element. 3973 * 3974 * For assistance with handling the uploaded file correctly, see the API 3975 * provided by file.inc. 3976 * 3977 * @param $variables 3978 * An associative array containing: 3979 * - element: An associative array containing the properties of the element. 3980 * Properties used: #title, #name, #size, #description, #required, 3981 * #attributes. 3982 * 3983 * @ingroup themeable 3984 */ 3985 function theme_file($variables) { 3986 $element = $variables['element']; 3987 $element['#attributes']['type'] = 'file'; 3988 element_set_attributes($element, array('id', 'name', 'size')); 3989 _form_set_class($element, array('form-file')); 3990 3991 return '<input' . drupal_attributes($element['#attributes']) . ' />'; 3992 } 3993 3994 /** 3995 * Returns HTML for a form element. 3996 * 3997 * Each form element is wrapped in a DIV container having the following CSS 3998 * classes: 3999 * - form-item: Generic for all form elements. 4000 * - form-type-#type: The internal element #type. 4001 * - form-item-#name: The internal form element #name (usually derived from the 4002 * $form structure and set via form_builder()). 4003 * - form-disabled: Only set if the form element is #disabled. 4004 * 4005 * In addition to the element itself, the DIV contains a label for the element 4006 * based on the optional #title_display property, and an optional #description. 4007 * 4008 * The optional #title_display property can have these values: 4009 * - before: The label is output before the element. This is the default. 4010 * The label includes the #title and the required marker, if #required. 4011 * - after: The label is output after the element. For example, this is used 4012 * for radio and checkbox #type elements as set in system_element_info(). 4013 * If the #title is empty but the field is #required, the label will 4014 * contain only the required marker. 4015 * - invisible: Labels are critical for screen readers to enable them to 4016 * properly navigate through forms but can be visually distracting. This 4017 * property hides the label for everyone except screen readers. 4018 * - attribute: Set the title attribute on the element to create a tooltip 4019 * but output no label element. This is supported only for checkboxes 4020 * and radios in form_pre_render_conditional_form_element(). It is used 4021 * where a visual label is not needed, such as a table of checkboxes where 4022 * the row and column provide the context. The tooltip will include the 4023 * title and required marker. 4024 * 4025 * If the #title property is not set, then the label and any required marker 4026 * will not be output, regardless of the #title_display or #required values. 4027 * This can be useful in cases such as the password_confirm element, which 4028 * creates children elements that have their own labels and required markers, 4029 * but the parent element should have neither. Use this carefully because a 4030 * field without an associated label can cause accessibility challenges. 4031 * 4032 * @param $variables 4033 * An associative array containing: 4034 * - element: An associative array containing the properties of the element. 4035 * Properties used: #title, #title_display, #description, #id, #required, 4036 * #children, #type, #name. 4037 * 4038 * @ingroup themeable 4039 */ 4040 function theme_form_element($variables) { 4041 $element = &$variables['element']; 4042 // This is also used in the installer, pre-database setup. 4043 $t = get_t(); 4044 4045 // This function is invoked as theme wrapper, but the rendered form element 4046 // may not necessarily have been processed by form_builder(). 4047 $element += array( 4048 '#title_display' => 'before', 4049 ); 4050 4051 // Add element #id for #type 'item'. 4052 if (isset($element['#markup']) && !empty($element['#id'])) { 4053 $attributes['id'] = $element['#id']; 4054 } 4055 // Add element's #type and #name as class to aid with JS/CSS selectors. 4056 $attributes['class'] = array('form-item'); 4057 if (!empty($element['#type'])) { 4058 $attributes['class'][] = 'form-type-' . strtr($element['#type'], '_', '-'); 4059 } 4060 if (!empty($element['#name'])) { 4061 $attributes['class'][] = 'form-item-' . strtr($element['#name'], array(' ' => '-', '_' => '-', '[' => '-', ']' => '')); 4062 } 4063 // Add a class for disabled elements to facilitate cross-browser styling. 4064 if (!empty($element['#attributes']['disabled'])) { 4065 $attributes['class'][] = 'form-disabled'; 4066 } 4067 $output = '<div' . drupal_attributes($attributes) . '>' . "\n"; 4068 4069 // If #title is not set, we don't display any label or required marker. 4070 if (!isset($element['#title'])) { 4071 $element['#title_display'] = 'none'; 4072 } 4073 $prefix = isset($element['#field_prefix']) ? '<span class="field-prefix">' . $element['#field_prefix'] . '</span> ' : ''; 4074 $suffix = isset($element['#field_suffix']) ? ' <span class="field-suffix">' . $element['#field_suffix'] . '</span>' : ''; 4075 4076 switch ($element['#title_display']) { 4077 case 'before': 4078 case 'invisible': 4079 $output .= ' ' . theme('form_element_label', $variables); 4080 $output .= ' ' . $prefix . $element['#children'] . $suffix . "\n"; 4081 break; 4082 4083 case 'after': 4084 $output .= ' ' . $prefix . $element['#children'] . $suffix; 4085 $output .= ' ' . theme('form_element_label', $variables) . "\n"; 4086 break; 4087 4088 case 'none': 4089 case 'attribute': 4090 // Output no label and no required marker, only the children. 4091 $output .= ' ' . $prefix . $element['#children'] . $suffix . "\n"; 4092 break; 4093 } 4094 4095 if (!empty($element['#description'])) { 4096 $output .= '<div class="description">' . $element['#description'] . "</div>\n"; 4097 } 4098 4099 $output .= "</div>\n"; 4100 4101 return $output; 4102 } 4103 4104 /** 4105 * Returns HTML for a marker for required form elements. 4106 * 4107 * @param $variables 4108 * An associative array containing: 4109 * - element: An associative array containing the properties of the element. 4110 * 4111 * @ingroup themeable 4112 */ 4113 function theme_form_required_marker($variables) { 4114 // This is also used in the installer, pre-database setup. 4115 $t = get_t(); 4116 $attributes = array( 4117 'class' => 'form-required', 4118 'title' => $t('This field is required.'), 4119 ); 4120 return '<span' . drupal_attributes($attributes) . '>*</span>'; 4121 } 4122 4123 /** 4124 * Returns HTML for a form element label and required marker. 4125 * 4126 * Form element labels include the #title and a #required marker. The label is 4127 * associated with the element itself by the element #id. Labels may appear 4128 * before or after elements, depending on theme_form_element() and 4129 * #title_display. 4130 * 4131 * This function will not be called for elements with no labels, depending on 4132 * #title_display. For elements that have an empty #title and are not required, 4133 * this function will output no label (''). For required elements that have an 4134 * empty #title, this will output the required marker alone within the label. 4135 * The label will use the #id to associate the marker with the field that is 4136 * required. That is especially important for screenreader users to know 4137 * which field is required. 4138 * 4139 * @param $variables 4140 * An associative array containing: 4141 * - element: An associative array containing the properties of the element. 4142 * Properties used: #required, #title, #id, #value, #description. 4143 * 4144 * @ingroup themeable 4145 */ 4146 function theme_form_element_label($variables) { 4147 $element = $variables['element']; 4148 // This is also used in the installer, pre-database setup. 4149 $t = get_t(); 4150 4151 // If title and required marker are both empty, output no label. 4152 if ((!isset($element['#title']) || $element['#title'] === '') && empty($element['#required'])) { 4153 return ''; 4154 } 4155 4156 // If the element is required, a required marker is appended to the label. 4157 $required = !empty($element['#required']) ? theme('form_required_marker', array('element' => $element)) : ''; 4158 4159 $title = filter_xss_admin($element['#title']); 4160 4161 $attributes = array(); 4162 // Style the label as class option to display inline with the element. 4163 if ($element['#title_display'] == 'after') { 4164 $attributes['class'] = 'option'; 4165 } 4166 // Show label only to screen readers to avoid disruption in visual flows. 4167 elseif ($element['#title_display'] == 'invisible') { 4168 $attributes['class'] = 'element-invisible'; 4169 } 4170 4171 if (!empty($element['#id'])) { 4172 $attributes['for'] = $element['#id']; 4173 } 4174 4175 // The leading whitespace helps visually separate fields from inline labels. 4176 return ' <label' . drupal_attributes($attributes) . '>' . $t('!title !required', array('!title' => $title, '!required' => $required)) . "</label>\n"; 4177 } 4178 4179 /** 4180 * Sets a form element's class attribute. 4181 * 4182 * Adds 'required' and 'error' classes as needed. 4183 * 4184 * @param $element 4185 * The form element. 4186 * @param $name 4187 * Array of new class names to be added. 4188 */ 4189 function _form_set_class(&$element, $class = array()) { 4190 if (!empty($class)) { 4191 if (!isset($element['#attributes']['class'])) { 4192 $element['#attributes']['class'] = array(); 4193 } 4194 $element['#attributes']['class'] = array_merge($element['#attributes']['class'], $class); 4195 } 4196 // This function is invoked from form element theme functions, but the 4197 // rendered form element may not necessarily have been processed by 4198 // form_builder(). 4199 if (!empty($element['#required'])) { 4200 $element['#attributes']['class'][] = 'required'; 4201 } 4202 if (isset($element['#parents']) && form_get_error($element) !== NULL) { 4203 $element['#attributes']['class'][] = 'error'; 4204 } 4205 } 4206 4207 /** 4208 * Form element validation handler for integer elements. 4209 */ 4210 function element_validate_integer($element, &$form_state) { 4211 $value = $element['#value']; 4212 if ($value !== '' && (!is_numeric($value) || intval($value) != $value)) { 4213 form_error($element, t('%name must be an integer.', array('%name' => $element['#title']))); 4214 } 4215 } 4216 4217 /** 4218 * Form element validation handler for integer elements that must be positive. 4219 */ 4220 function element_validate_integer_positive($element, &$form_state) { 4221 $value = $element['#value']; 4222 if ($value !== '' && (!is_numeric($value) || intval($value) != $value || $value <= 0)) { 4223 form_error($element, t('%name must be a positive integer.', array('%name' => $element['#title']))); 4224 } 4225 } 4226 4227 /** 4228 * Form element validation handler for number elements. 4229 */ 4230 function element_validate_number($element, &$form_state) { 4231 $value = $element['#value']; 4232 if ($value != '' && !is_numeric($value)) { 4233 form_error($element, t('%name must be a number.', array('%name' => $element['#title']))); 4234 } 4235 } 4236 4237 /** 4238 * @} End of "defgroup form_api". 4239 */ 4240 4241 /** 4242 * @defgroup batch Batch operations 4243 * @{ 4244 * Creates and processes batch operations. 4245 * 4246 * Functions allowing forms processing to be spread out over several page 4247 * requests, thus ensuring that the processing does not get interrupted 4248 * because of a PHP timeout, while allowing the user to receive feedback 4249 * on the progress of the ongoing operations. 4250 * 4251 * The API is primarily designed to integrate nicely with the Form API 4252 * workflow, but can also be used by non-Form API scripts (like update.php) 4253 * or even simple page callbacks (which should probably be used sparingly). 4254 * 4255 * Example: 4256 * @code 4257 * $batch = array( 4258 * 'title' => t('Exporting'), 4259 * 'operations' => array( 4260 * array('my_function_1', array($account->uid, 'story')), 4261 * array('my_function_2', array()), 4262 * ), 4263 * 'finished' => 'my_finished_callback', 4264 * 'file' => 'path_to_file_containing_myfunctions', 4265 * ); 4266 * batch_set($batch); 4267 * // Only needed if not inside a form _submit handler. 4268 * // Setting redirect in batch_process. 4269 * batch_process('node/1'); 4270 * @endcode 4271 * 4272 * Note: if the batch 'title', 'init_message', 'progress_message', or 4273 * 'error_message' could contain any user input, it is the responsibility of 4274 * the code calling batch_set() to sanitize them first with a function like 4275 * check_plain() or filter_xss(). Furthermore, if the batch operation 4276 * returns any user input in the 'results' or 'message' keys of $context, 4277 * it must also sanitize them first. 4278 * 4279 * Sample batch operations: 4280 * @code 4281 * // Simple and artificial: load a node of a given type for a given user 4282 * function my_function_1($uid, $type, &$context) { 4283 * // The $context array gathers batch context information about the execution (read), 4284 * // as well as 'return values' for the current operation (write) 4285 * // The following keys are provided : 4286 * // 'results' (read / write): The array of results gathered so far by 4287 * // the batch processing, for the current operation to append its own. 4288 * // 'message' (write): A text message displayed in the progress page. 4289 * // The following keys allow for multi-step operations : 4290 * // 'sandbox' (read / write): An array that can be freely used to 4291 * // store persistent data between iterations. It is recommended to 4292 * // use this instead of $_SESSION, which is unsafe if the user 4293 * // continues browsing in a separate window while the batch is processing. 4294 * // 'finished' (write): A float number between 0 and 1 informing 4295 * // the processing engine of the completion level for the operation. 4296 * // 1 (or no value explicitly set) means the operation is finished 4297 * // and the batch processing can continue to the next operation. 4298 * 4299 * $node = node_load(array('uid' => $uid, 'type' => $type)); 4300 * $context['results'][] = $node->nid . ' : ' . check_plain($node->title); 4301 * $context['message'] = check_plain($node->title); 4302 * } 4303 * 4304 * // More advanced example: multi-step operation - load all nodes, five by five 4305 * function my_function_2(&$context) { 4306 * if (empty($context['sandbox'])) { 4307 * $context['sandbox']['progress'] = 0; 4308 * $context['sandbox']['current_node'] = 0; 4309 * $context['sandbox']['max'] = db_query('SELECT COUNT(DISTINCT nid) FROM {node}')->fetchField(); 4310 * } 4311 * $limit = 5; 4312 * $result = db_select('node') 4313 * ->fields('node', array('nid')) 4314 * ->condition('nid', $context['sandbox']['current_node'], '>') 4315 * ->orderBy('nid') 4316 * ->range(0, $limit) 4317 * ->execute(); 4318 * foreach ($result as $row) { 4319 * $node = node_load($row->nid, NULL, TRUE); 4320 * $context['results'][] = $node->nid . ' : ' . check_plain($node->title); 4321 * $context['sandbox']['progress']++; 4322 * $context['sandbox']['current_node'] = $node->nid; 4323 * $context['message'] = check_plain($node->title); 4324 * } 4325 * if ($context['sandbox']['progress'] != $context['sandbox']['max']) { 4326 * $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max']; 4327 * } 4328 * } 4329 * @endcode 4330 * 4331 * Sample 'finished' callback: 4332 * @code 4333 * function batch_test_finished($success, $results, $operations) { 4334 * // The 'success' parameter means no fatal PHP errors were detected. All 4335 * // other error management should be handled using 'results'. 4336 * if ($success) { 4337 * $message = format_plural(count($results), 'One post processed.', '@count posts processed.'); 4338 * } 4339 * else { 4340 * $message = t('Finished with an error.'); 4341 * } 4342 * drupal_set_message($message); 4343 * // Providing data for the redirected page is done through $_SESSION. 4344 * foreach ($results as $result) { 4345 * $items[] = t('Loaded node %title.', array('%title' => $result)); 4346 * } 4347 * $_SESSION['my_batch_results'] = $items; 4348 * } 4349 * @endcode 4350 */ 4351 4352 /** 4353 * Adds a new batch. 4354 * 4355 * Batch operations are added as new batch sets. Batch sets are used to spread 4356 * processing (primarily, but not exclusively, forms processing) over several 4357 * page requests. This helps to ensure that the processing is not interrupted 4358 * due to PHP timeouts, while users are still able to receive feedback on the 4359 * progress of the ongoing operations. Combining related operations into 4360 * distinct batch sets provides clean code independence for each batch set, 4361 * ensuring that two or more batches, submitted independently, can be processed 4362 * without mutual interference. Each batch set may specify its own set of 4363 * operations and results, produce its own UI messages, and trigger its own 4364 * 'finished' callback. Batch sets are processed sequentially, with the progress 4365 * bar starting afresh for each new set. 4366 * 4367 * @param $batch_definition 4368 * An associative array defining the batch, with the following elements (all 4369 * are optional except as noted): 4370 * - operations: (required) Array of function calls to be performed. 4371 * Example: 4372 * @code 4373 * array( 4374 * array('my_function_1', array($arg1)), 4375 * array('my_function_2', array($arg2_1, $arg2_2)), 4376 * ) 4377 * @endcode 4378 * - title: A safe, translated string to use as the title for the progress 4379 * page. Defaults to t('Processing'). 4380 * - init_message: Message displayed while the processing is initialized. 4381 * Defaults to t('Initializing.'). 4382 * - progress_message: Message displayed while processing the batch. Available 4383 * placeholders are @current, @remaining, @total, @percentage, @estimate and 4384 * @elapsed. Defaults to t('Completed @current of @total.'). 4385 * - error_message: Message displayed if an error occurred while processing 4386 * the batch. Defaults to t('An error has occurred.'). 4387 * - finished: Name of a function to be executed after the batch has 4388 * completed. This should be used to perform any result massaging that may 4389 * be needed, and possibly save data in $_SESSION for display after final 4390 * page redirection. 4391 * - file: Path to the file containing the definitions of the 'operations' and 4392 * 'finished' functions, for instance if they don't reside in the main 4393 * .module file. The path should be relative to base_path(), and thus should 4394 * be built using drupal_get_path(). 4395 * - css: Array of paths to CSS files to be used on the progress page. 4396 * - url_options: options passed to url() when constructing redirect URLs for 4397 * the batch. 4398 */ 4399 function batch_set($batch_definition) { 4400 if ($batch_definition) { 4401 $batch =& batch_get(); 4402 4403 // Initialize the batch if needed. 4404 if (empty($batch)) { 4405 $batch = array( 4406 'sets' => array(), 4407 'has_form_submits' => FALSE, 4408 ); 4409 } 4410 4411 // Base and default properties for the batch set. 4412 // Use get_t() to allow batches during installation. 4413 $t = get_t(); 4414 $init = array( 4415 'sandbox' => array(), 4416 'results' => array(), 4417 'success' => FALSE, 4418 'start' => 0, 4419 'elapsed' => 0, 4420 ); 4421 $defaults = array( 4422 'title' => $t('Processing'), 4423 'init_message' => $t('Initializing.'), 4424 'progress_message' => $t('Completed @current of @total.'), 4425 'error_message' => $t('An error has occurred.'), 4426 'css' => array(), 4427 ); 4428 $batch_set = $init + $batch_definition + $defaults; 4429 4430 // Tweak init_message to avoid the bottom of the page flickering down after 4431 // init phase. 4432 $batch_set['init_message'] .= '<br/> '; 4433 4434 // The non-concurrent workflow of batch execution allows us to save 4435 // numberOfItems() queries by handling our own counter. 4436 $batch_set['total'] = count($batch_set['operations']); 4437 $batch_set['count'] = $batch_set['total']; 4438 4439 // Add the set to the batch. 4440 if (empty($batch['id'])) { 4441 // The batch is not running yet. Simply add the new set. 4442 $batch['sets'][] = $batch_set; 4443 } 4444 else { 4445 // The set is being added while the batch is running. Insert the new set 4446 // right after the current one to ensure execution order, and store its 4447 // operations in a queue. 4448 $index = $batch['current_set'] + 1; 4449 $slice1 = array_slice($batch['sets'], 0, $index); 4450 $slice2 = array_slice($batch['sets'], $index); 4451 $batch['sets'] = array_merge($slice1, array($batch_set), $slice2); 4452 _batch_populate_queue($batch, $index); 4453 } 4454 } 4455 } 4456 4457 /** 4458 * Processes the batch. 4459 * 4460 * Unless the batch has been marked with 'progressive' = FALSE, the function 4461 * issues a drupal_goto and thus ends page execution. 4462 * 4463 * This function is generally not needed in form submit handlers; 4464 * Form API takes care of batches that were set during form submission. 4465 * 4466 * @param $redirect 4467 * (optional) Path to redirect to when the batch has finished processing. 4468 * @param $url 4469 * (optional - should only be used for separate scripts like update.php) 4470 * URL of the batch processing page. 4471 * @param $redirect_callback 4472 * (optional) Specify a function to be called to redirect to the progressive 4473 * processing page. By default drupal_goto() will be used to redirect to a 4474 * page which will do the progressive page. Specifying another function will 4475 * allow the progressive processing to be processed differently. 4476 */ 4477 function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = 'drupal_goto') { 4478 $batch =& batch_get(); 4479 4480 drupal_theme_initialize(); 4481 4482 if (isset($batch)) { 4483 // Add process information 4484 $process_info = array( 4485 'current_set' => 0, 4486 'progressive' => TRUE, 4487 'url' => $url, 4488 'url_options' => array(), 4489 'source_url' => $_GET['q'], 4490 'redirect' => $redirect, 4491 'theme' => $GLOBALS['theme_key'], 4492 'redirect_callback' => $redirect_callback, 4493 ); 4494 $batch += $process_info; 4495 4496 // The batch is now completely built. Allow other modules to make changes 4497 // to the batch so that it is easier to reuse batch processes in other 4498 // environments. 4499 drupal_alter('batch', $batch); 4500 4501 // Assign an arbitrary id: don't rely on a serial column in the 'batch' 4502 // table, since non-progressive batches skip database storage completely. 4503 $batch['id'] = db_next_id(); 4504 4505 // Move operations to a job queue. Non-progressive batches will use a 4506 // memory-based queue. 4507 foreach ($batch['sets'] as $key => $batch_set) { 4508 _batch_populate_queue($batch, $key); 4509 } 4510 4511 // Initiate processing. 4512 if ($batch['progressive']) { 4513 // Now that we have a batch id, we can generate the redirection link in 4514 // the generic error message. 4515 $t = get_t(); 4516 $batch['error_message'] = $t('Please continue to <a href="@error_url">the error page</a>', array('@error_url' => url($url, array('query' => array('id' => $batch['id'], 'op' => 'finished'))))); 4517 4518 // Clear the way for the drupal_goto() redirection to the batch processing 4519 // page, by saving and unsetting the 'destination', if there is any. 4520 if (isset($_GET['destination'])) { 4521 $batch['destination'] = $_GET['destination']; 4522 unset($_GET['destination']); 4523 } 4524 4525 // Store the batch. 4526 db_insert('batch') 4527 ->fields(array( 4528 'bid' => $batch['id'], 4529 'timestamp' => REQUEST_TIME, 4530 'token' => drupal_get_token($batch['id']), 4531 'batch' => serialize($batch), 4532 )) 4533 ->execute(); 4534 4535 // Set the batch number in the session to guarantee that it will stay alive. 4536 $_SESSION['batches'][$batch['id']] = TRUE; 4537 4538 // Redirect for processing. 4539 $function = $batch['redirect_callback']; 4540 if (function_exists($function)) { 4541 $function($batch['url'], array('query' => array('op' => 'start', 'id' => $batch['id']))); 4542 } 4543 } 4544 else { 4545 // Non-progressive execution: bypass the whole progressbar workflow 4546 // and execute the batch in one pass. 4547 require_once DRUPAL_ROOT . '/includes/batch.inc'; 4548 _batch_process(); 4549 } 4550 } 4551 } 4552 4553 /** 4554 * Retrieves the current batch. 4555 */ 4556 function &batch_get() { 4557 // Not drupal_static(), because Batch API operates at a lower level than most 4558 // use-cases for resetting static variables, and we specifically do not want a 4559 // global drupal_static_reset() resetting the batch information. Functions 4560 // that are part of the Batch API and need to reset the batch information may 4561 // call batch_get() and manipulate the result by reference. Functions that are 4562 // not part of the Batch API can also do this, but shouldn't. 4563 static $batch = array(); 4564 return $batch; 4565 } 4566 4567 /** 4568 * Populates a job queue with the operations of a batch set. 4569 * 4570 * Depending on whether the batch is progressive or not, the BatchQueue or 4571 * BatchMemoryQueue handler classes will be used. 4572 * 4573 * @param $batch 4574 * The batch array. 4575 * @param $set_id 4576 * The id of the set to process. 4577 * 4578 * @return 4579 * The name and class of the queue are added by reference to the batch set. 4580 */ 4581 function _batch_populate_queue(&$batch, $set_id) { 4582 $batch_set = &$batch['sets'][$set_id]; 4583 4584 if (isset($batch_set['operations'])) { 4585 $batch_set += array( 4586 'queue' => array( 4587 'name' => 'drupal_batch:' . $batch['id'] . ':' . $set_id, 4588 'class' => $batch['progressive'] ? 'BatchQueue' : 'BatchMemoryQueue', 4589 ), 4590 ); 4591 4592 $queue = _batch_queue($batch_set); 4593 $queue->createQueue(); 4594 foreach ($batch_set['operations'] as $operation) { 4595 $queue->createItem($operation); 4596 } 4597 4598 unset($batch_set['operations']); 4599 } 4600 } 4601 4602 /** 4603 * Returns a queue object for a batch set. 4604 * 4605 * @param $batch_set 4606 * The batch set. 4607 * 4608 * @return 4609 * The queue object. 4610 */ 4611 function _batch_queue($batch_set) { 4612 static $queues; 4613 4614 // The class autoloader is not available when running update.php, so make 4615 // sure the files are manually included. 4616 if (!isset($queues)) { 4617 $queues = array(); 4618 require_once DRUPAL_ROOT . '/modules/system/system.queue.inc'; 4619 require_once DRUPAL_ROOT . '/includes/batch.queue.inc'; 4620 } 4621 4622 if (isset($batch_set['queue'])) { 4623 $name = $batch_set['queue']['name']; 4624 $class = $batch_set['queue']['class']; 4625 4626 if (!isset($queues[$class][$name])) { 4627 $queues[$class][$name] = new $class($name); 4628 } 4629 return $queues[$class][$name]; 4630 } 4631 } 4632 4633 /** 4634 * @} End of "defgroup batch". 4635 */
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
title