diff --git a/includes/form.inc b/includes/form.inc index 60b870709d6..60b39a86431 100644 --- a/includes/form.inc +++ b/includes/form.inc @@ -126,8 +126,10 @@ function drupal_get_form($form_id) { * common elements, such as back/next/save buttons in multi-step form * wizards, may define a form builder function name that returns a form * structure, which is passed on to the actual form builder function. - * Such forms cannot use drupal_get_form() and need to prepare $form_state - * on their own. + * Such implementations may either define the 'wrapper_callback' via + * hook_forms() or have to invoke drupal_build_form() (instead of + * drupal_get_form()) on their own in a custom menu callback to prepare + * $form_state accordingly. * Further $form_state properties controlling the redirection behavior after * form submission may be found in drupal_redirect_form(). * @@ -479,8 +481,19 @@ function drupal_retrieve_form($form_id, &$form_state) { if (isset($form_definition['callback'])) { $callback = $form_definition['callback']; } + // In case $form_state['wrapper_callback'] is not defined already, we also + // allow hook_forms() to define one. + if (!isset($form_state['wrapper_callback']) && isset($form_definition['wrapper_callback'])) { + $form_state['wrapper_callback'] = $form_definition['wrapper_callback']; + } } + $form = array(); + // We need to pass $form_state by reference in order for forms to modify it, + // since call_user_func_array() requires that referenced variables are passed + // explicitly. + $args = array_merge(array($form, &$form_state), $args); + // When the passed $form_state (not using drupal_get_form()) defines a // 'wrapper_callback', then it requests to invoke a separate (wrapping) form // builder function to pre-populate the $form array with form elements, which @@ -488,14 +501,11 @@ function drupal_retrieve_form($form_id, &$form_state) { // pre-populating a form with common elements for certain forms, such as // back/next/save buttons in multi-step form wizards. // @see drupal_build_form() - $form = array(); if (isset($form_state['wrapper_callback']) && function_exists($form_state['wrapper_callback'])) { - $form = $form_state['wrapper_callback']($form, $form_state); + $form = call_user_func_array($form_state['wrapper_callback'], $args); + // Put the prepopulated $form into $args. + $args[0] = $form; } - // We need to pass $form_state by reference in order for forms to modify it, - // since call_user_func_array() requires that referenced variables be passed - // explicitly. - $args = array_merge(array($form, &$form_state), $args); // If $callback was returned by a hook_forms() implementation, call it. // Otherwise, call the function named after the form id. diff --git a/modules/color/color.module b/modules/color/color.module index 882d23cba82..7f6f47b31ff 100644 --- a/modules/color/color.module +++ b/modules/color/color.module @@ -139,8 +139,7 @@ function color_get_palette($theme, $default = FALSE) { /** * Form callback. Returns the configuration form. */ -function color_scheme_form($form, &$form_state, $theme) { - $form = array(); +function color_scheme_form($complete_form, &$form_state, $theme) { $base = drupal_get_path('module', 'color'); $info = color_get_info($theme); diff --git a/modules/node/node.module b/modules/node/node.module index 735fc30c4c9..67990084c44 100644 --- a/modules/node/node.module +++ b/modules/node/node.module @@ -1480,7 +1480,6 @@ function node_search_status() { * Implement hook_search_admin(). */ function node_search_admin() { - $form = array(); // Output form for defining rank factor weights. $form['content_ranking'] = array( '#type' => 'fieldset', diff --git a/modules/simpletest/tests/form.test b/modules/simpletest/tests/form.test index f0302ff47bd..c1271c45961 100644 --- a/modules/simpletest/tests/form.test +++ b/modules/simpletest/tests/form.test @@ -321,13 +321,10 @@ class FormsElementsTableSelectFunctionalTest extends DrupalWebTestCase { * @return * An array containing the processed form, the form_state and any errors. */ - private function formSubmitHelper($form_element, $edit) { + private function formSubmitHelper($form, $edit) { $form_id = $this->randomName(); - $form_state = form_state_defaults(); - $form = array(); - $form = array_merge($form, $form_element); $form['op'] = array('#type' => 'submit', '#value' => t('Submit')); $form_state['input'] = $edit; diff --git a/modules/system/system.api.php b/modules/system/system.api.php index 339f82d04ea..327f6c56965 100644 --- a/modules/system/system.api.php +++ b/modules/system/system.api.php @@ -645,9 +645,11 @@ function hook_form_system_theme_settings_alter(&$form, &$form_state) { * function but each form will have a different form id for submission, * validation, theming or alteration by other modules. * - * The callback arguments will be passed as parameters to the function. Callers - * of drupal_get_form() are also able to pass in parameters. These will be - * appended after those specified by hook_forms(). + * The 'callback arguments' will be passed as parameters to the function defined + * in 'callback'. In case the code that calls drupal_get_form() also passes + * parameters, then the 'callback' function will receive the + * 'callback arguments' specified in hook_forms() before those that have been + * passed to drupal_get_form(). * * See node_forms() for an actual example of how multiple forms share a common * building function. @@ -656,16 +658,44 @@ function hook_form_system_theme_settings_alter(&$form, &$form_state) { * The unique string identifying the desired form. * @param $args * An array containing the original arguments provided to drupal_get_form(). + * These are always passed to the form builder and do not have to be specified + * manually in 'callback arguments'. + * * @return - * An array keyed by form_id with callbacks and optional, callback arguments. + * An associative array whose keys define form_ids and whose values are an + * associative array defining the following keys: + * - callback: The name of the form builder function to invoke. + * - callback arguments: (optional) Additional arguments to pass to the + * function defined in 'callback', which are prepended to $args. + * - wrapper_callback: (optional) The name of a form builder function to + * invoke before the form builder defined in 'callback' is invoked. This + * wrapper callback may prepopulate the $form array with form elements, + * which will then be already contained in the $form that is passed on to + * the form builder defined in 'callback'. For example, a wrapper callback + * could setup wizard-alike form buttons that are the same for a variety of + * forms that belong to the wizard, which all share the same wrapper + * callback. */ function hook_forms($form_id, $args) { + // Simply reroute the (non-existing) $form_id 'mymodule_first_form' to + // 'mymodule_main_form'. $forms['mymodule_first_form'] = array( - 'callback' => 'mymodule_form_builder', + 'callback' => 'mymodule_main_form', + ); + + // Reroute the $form_id and prepend an additional argument that gets passed to + // the 'mymodule_main_form' form builder function. + $forms['mymodule_second_form'] = array( + 'callback' => 'mymodule_main_form', 'callback arguments' => array('some parameter'), ); - $forms['mymodule_second_form'] = array( - 'callback' => 'mymodule_form_builder', + + // Reroute the $form_id, but invoke the form builder function + // 'mymodule_main_form_wrapper' first, so we can prepopulate the $form array + // that is passed to the actual form builder 'mymodule_main_form'. + $forms['mymodule_wrapped_form'] = array( + 'callback' => 'mymodule_main_form', + 'wrapper_callback' => 'mymodule_main_form_wrapper', ); return $forms; diff --git a/update.php b/update.php index 2d4f1e50ed8..e9e5c84f6ac 100644 --- a/update.php +++ b/update.php @@ -37,8 +37,7 @@ function update_selection_page() { return $output; } -function update_script_selection_form() { - $form = array(); +function update_script_selection_form($form, &$form_state) { $count = 0; $form['start'] = array( '#tree' => TRUE,