Commit 4615c96d authored by Gábor Hojtsy's avatar Gábor Hojtsy
Browse files

#193191 by chx: allow form elements to enable form caching - allows custom...

#193191 by chx: allow form elements to enable form caching - allows custom form elements to leverage the AHAH framework
parent c1555f33
......@@ -51,6 +51,7 @@ function drupal_get_form($form_id) {
$form_state = array('storage' => NULL, 'submitted' => FALSE);
$args = func_get_args();
$cacheable = FALSE;
if (isset($_SESSION['batch_form_state'])) {
// We've been redirected here after a batch processing : the form has
......@@ -84,11 +85,10 @@ function drupal_get_form($form_id) {
$form_build_id = 'form-'. md5(mt_rand());
$form['#build_id'] = $form_build_id;
drupal_prepare_form($form_id, $form, $form_state);
if (!empty($form['#cache'])) {
// By not sending the form state, we avoid storing the storage which
// won't have been touched yet.
form_set_cache($form_build_id, $form, NULL);
}
// Store a copy of the unprocessed form for caching and indicate that it
// is cacheable if #cache will be set.
$original_form = $form;
$cacheable = TRUE;
unset($form_state['post']);
}
$form['#post'] = $_POST;
......@@ -99,6 +99,12 @@ function drupal_get_form($form_id) {
// altering the $form_state variable, which is passed into them by
// reference.
drupal_process_form($form_id, $form, $form_state);
if ($cacheable && !empty($form['#cache'])) {
// Caching is done past drupal_process_form so #process callbacks can
// set #cache. By not sending the form state, we avoid storing
// $form_state['storage'].
form_set_cache($form_build_id, $original_form, NULL);
}
}
// Most simple, single-step forms will be finished by this point --
......@@ -116,27 +122,7 @@ function drupal_get_form($form_id) {
// other variables passed into drupal_get_form().
if (!empty($form_state['rebuild']) || !empty($form_state['storage'])) {
array_shift($args);
array_unshift($args, $form_state);
array_unshift($args, $form_id);
$form = call_user_func_array('drupal_retrieve_form', $args);
// We need a new build_id for the new version of the form.
$form_build_id = 'form-'. md5(mt_rand());
$form['#build_id'] = $form_build_id;
drupal_prepare_form($form_id, $form, $form_state);
// Now, we cache the form structure so it can be retrieved later for
// validation. If $form_state['storage'] is populated, we'll also cache
// it so that it can be used to resume complex multi-step processes.
form_set_cache($form_build_id, $form, $form_state);
// Clear out all post data, as we don't want the previous step's
// data to pollute this one and trigger validate/submit handling,
// then process the form for rendering.
$_POST = array();
$form['#post'] = array();
drupal_process_form($form_id, $form, $form_state);
$form = drupal_rebuild_form($form_id, $form_state, $args);
}
// If we haven't redirected to a new location by now, we want to
......@@ -144,6 +130,75 @@ function drupal_get_form($form_id) {
return drupal_render_form($form_id, $form);
}
/**
* Retrieves a form, caches it and processes it with an empty $_POST.
*
* This function clears $_POST and passes the empty $_POST to the form_builder.
* To preserve some parts from $_POST, pass them in $form_state.
*
* If your AHAH callback simulates the pressing of a button, then your AHAH
* callback will need to do the same as what drupal_get_form would do when the
* button is pressed: get the form from the cache, run drupal_process_form over
* it and then if it needs rebuild, run drupal_rebuild_form over it. Then send
* back a part of the returned form.
* $form_state['clicked_button']['#array_parents'] will help you to find which
* part.
*
* @param $form_id
* The unique string identifying the desired form. If a function
* with that name exists, it is called to build the form array.
* Modules that need to generate the same form (or very similar forms)
* using different $form_ids can implement hook_forms(), which maps
* different $form_id values to the proper form constructor function. Examples
* may be found in node_forms(), search_forms(), and user_forms().
* @param $form_state
* A keyed array containing the current state of the form. Most
* important is the $form_state['storage'] collection.
* @param $args
* Any additional arguments are passed on to the functions called by
* drupal_get_form(), plus the original form_state in the beginning. If you
* are getting a form from the cache, use $form['#parameters'] to shift off
* the $form_id from its beginning then the resulting array can be used as
* $arg here.
* @param $form_build_id
* If the AHAH callback calling this function only alters part of the form,
* then pass in the existing form_build_id so we can re-cache with the same
* csid.
* @return
* The newly built form.
*/
function drupal_rebuild_form($form_id, &$form_state, $args, $form_build_id = NULL) {
// Remove the first argument. This is $form_id.when called from
// drupal_get_form and the original $form_state when called from some AHAH
// callback. Neither is needed.
array_shift($args);
// Put in the current state.
array_unshift($args, $form_state);
// And the form_id.
array_unshift($args, $form_id);
$form = call_user_func_array('drupal_retrieve_form', $args);
if (!isset($form_build_id)) {
// We need a new build_id for the new version of the form.
$form_build_id = 'form-'. md5(mt_rand());
}
$form['#build_id'] = $form_build_id;
drupal_prepare_form($form_id, $form, $form_state);
// Now, we cache the form structure so it can be retrieved later for
// validation. If $form_state['storage'] is populated, we'll also cache
// it so that it can be used to resume complex multi-step processes.
form_set_cache($form_build_id, $form, $form_state);
// Clear out all post data, as we don't want the previous step's
// data to pollute this one and trigger validate/submit handling,
// then process the form for rendering.
$_POST = array();
$form['#post'] = array();
drupal_process_form($form_id, $form, $form_state);
return $form;
}
/**
* Fetch a form from cache.
*/
......@@ -738,7 +793,7 @@ function form_error(&$element, $message = '') {
* $_POST data.
*/
function form_builder($form_id, $form, &$form_state) {
static $complete_form;
static $complete_form, $cache;
// Initialize as unprocessed.
$form['#processed'] = FALSE;
......@@ -784,6 +839,9 @@ function form_builder($form_id, $form, &$form_state) {
// Check to see if a tree of child elements is present. If so,
// continue down the tree if required.
$form[$key]['#parents'] = $form[$key]['#tree'] && $form['#tree'] ? array_merge($form['#parents'], array($key)) : array($key);
$array_parents = isset($form['#array_parents']) ? $form['#array_parents'] : array();
$array_parents[] = $key;
$form[$key]['#array_parents'] = $array_parents;
}
// Assign a decimal placeholder weight to preserve original array order.
......@@ -815,6 +873,15 @@ function form_builder($form_id, $form, &$form_state) {
// After handling the special IE case, we no longer need the buttons collection.
unset($form_state['buttons']);
// If some callback set #cache, we need to flip a static flag so later it
// can be found.
if (isset($form['#cache'])) {
$cache = $form['#cache'];
}
// We are on the top form, we can copy back #cache if it's set.
if (isset($form['#type']) && $form['#type'] == 'form' && isset($cache)) {
$form['#cache'] = TRUE;
}
return $form;
}
......@@ -913,8 +980,7 @@ function _form_builder_handle_input_element($form_id, &$form, &$form_state, $com
if (isset($form['#process']) && !$form['#processed']) {
foreach ($form['#process'] as $process) {
if (function_exists($process)) {
$args = array_merge(array($form), array(isset($edit) ? $edit : NULL), array($form_state), array($complete_form));
$form = call_user_func_array($process, $args);
$form = $process($form, isset($edit) ? $edit : NULL, $form_state, $complete_form);
}
}
$form['#processed'] = TRUE;
......@@ -1669,6 +1735,7 @@ function form_expand_ahah($element) {
drupal_add_js(array('ahah' => array($element['#id'] => $ahah_binding)), 'setting');
$js_added[$element['#id']] = TRUE;
$element['#cache'] = TRUE;
}
return $element;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment