Not all forms need to be generated dynamically. There many cases in which a form will be the same for all inputs.
Yet, there are some forms that will require varying default values for a common set of fields.
So, many forms may be presented quickly without program execution for every use.

The following code snippet provides a high level outline of a way in which forms may be processed in order to achieve the higher throughput.

This is a change of drupal_render_form, where the change is only to code around drupal_render. As such the change could be implemented in any version after five, without affecting other aspects to mechanisms of form retrieval.

I have used the approach of just getting forms for a subclass of data in classydex,, www.classydex.com. These forms are all very similar. They can bring in their own CSS and can contain information about payment or not, etc. The retrieval of the forms is fairly rapid. I found that getting javascript for the entry was more difficult and that it was best to have each javascript dependency in a form already available on the page in which the form is made to reside. However, note that for classydex, forms are retrieved in response to Ajax calls while forms generated below are in the Drupal page context.

/**
 * Renders a structured form array into themed HTML.
 *
 * @param $form_id
 *   A unique string identifying the form for validation, submission,
 *   theming, and hook_form_alter functions.
 * @param $form
 *   An associative array containing the structure of the form.
 * @return
 *   A string containing the path of the page to display when processing
 *   is complete.
 */
function drupal_render_form($form_id, &$form) {
  // Don't override #theme if someone already set it.
  if (!isset($form['#theme'])) {
    init_theme();
    $registry = theme_get_registry();
    if (isset($registry[$form_id])) {
      $form['#theme'] = $form_id;
    }
  }
  
  $output = "\n<div id='panelbar'>\n";
  
  $formtext = "";
  if ( !changed_form($form_id,$form) && !dynamic_form($form_id,$form) ) {
    $formtext = fetch_prerendered_form($form_id); // As in get it from the DB..
    if ( is_array($formtext) ) { // If this form still needs information loaded into it
      $formtext = transfer_default_substitutions($formtext,$form); // Transfer default values in substitution entries. Return string finally...
    }
  }

  if ( $formtext != "" ) {  // Render it at least once.
    $formtext .= drupal_render($form);
    // Ask this question: Does this form now need to be stored? (Cache the form, put it into the DB.)
    if ( form_to_be_cached($form_id) ) {
      store_this_form($form_id,formtext);
    }
  }

  $output .= "\n</div>\n";

  return $output;
}

CommentFileSizeAuthor
#1 formdb.inc_.tar_.gz529 bytesrleddy

Comments

rleddy’s picture

StatusFileSize
new529 bytes

I just tried this out.... And, I corrected the error in the posted code.

SO, for 5.x here is another version of the subroutine...




function oat_header() {
  global $oatlocus;
  global $g_fieldsetCount;

  if ( $g_fieldsetCount ) {
    $module_path = base_path() . drupal_get_path('module', 'spellcheck');
    drupal_add_js("var gNum_fieldsets = $g_fieldsetCount;", 'inline');
  }
}




function query_form_description($form_id,$form) {
  static $loaded_forms = array();

  if ( count($loaded_forms) == 0 ) {
    // Get the modules to load the forms...
    $loaded_forms = module_invoke_all('registered_forms');
  }

  if ( ( count($loaded_forms) > 0 ) && ( isset($loaded_forms[$form_id]) ) ) {
    return($loaded_forms[$form_id]);
  }

  return(null);
}




function changed_form($form_id,$form) {

  $form_info = query_form_description($form_id,$form);

  if ( $form_info != null ) {
  
    if ( $form_info->dynamic ) {  // if the form is dynamic, it is always changing.
      return(true);
    } else {
      return($form_info->changed);
    }

  }

  return(true); 
}



function fetch_prerendered_form($form_id) {
  $form_info = query_form_description($form_id,$form);
  if ( $form_info != null ) {
    if ( strlen($form_info->substitutions_keys) == 0 ) {
      return($form_info->formtext); // let the modules get it from the DB.
    } else {
      return($form_info); // let the modules get it from the DB.
    }
  }
  return("FORM NOT RENDERED: " . $form_id);
}



function retrieve_form_defaults($form,$keysminor) {
  if ( isset($form['#default_value']) ) {
    return($form['#default_value']);
  }

  $subform = null;
  foreach( $keysminor as $key ) {
    $subform = &$form[$key];
  }

  if ( isset($subform['#default_value']) ) {
    return($subform['#default_value']);
  }

  return("");  
}


function transfer_default_substitutions($form_info,$form) {

  $formtext = $form_info->formtext;
  
  $subsitutions = $form_info->substitutions_keys;
  
  foreach( $subsitutions as $keymajor => $keysminor ) {
    $substval = retrieve_form_defaults($form,$keysminor);
    $formtext = str_replace($keymajor,$substval,$formtext);
  }

  return($formtext);
}



function form_to_be_cached($form_id) {
  $form_info = query_form_description($form_id,$form);
  if ( !isset($form_info) ) return(false);
  return( !($form_info->dynamic) );
}



function store_this_form($form_id,$formtext) {
  $form_info = query_form_description($form_id,$form);
  $form_info->formtext = $formtext;

  module_invoke_all('store_registered_form',$form_id,$form_info);
}





/**
 * Renders a structured form array into themed HTML.
 *
 * @param $form_id
 *   A unique string identifying the form for validation, submission,
 *   theming, and hook_form_alter functions.
 * @param $form
 *   An associative array containing the structure of the form.
 * @return
 *   A string containing the path of the page to display when processing
 *   is complete.
 *
 */
function drupal_render_form($form_id, &$form) {
  global $g_fieldsetCount;
  $g_fieldsetCount = 0;

  $base = null;
  // Don't override #theme if someone already set it.
  if (isset($form['#base'])) {
    $base = $form['#base'];
  }
  
  if (!isset($form['#theme'])) {
    if (theme_get_function($form_id)) {
      $form['#theme'] = $form_id;
    }
    elseif (theme_get_function($base)) {
      $form['#theme'] = $base;
    }
  }
  
  if (isset($form['#pre_render'])) {
    foreach ($form['#pre_render'] as $function) {
      if (function_exists($function)) {
        $function($form_id, $form);
      }
    }
  }
  
   drupal_set_html_head(oat_header($node));

  
  $output = "\n<div id='panelbar'>\n";

  query_form_description($form_id,$form);

  
  $formtext = "";
  if ( !changed_form($form_id,$form) ) {
    $formtext = fetch_prerendered_form($form_id); // As in get it from the DB..
    if ( is_object($formtext) ) { // If this form still needs information loaded into it
      $formtext = transfer_default_substitutions($formtext,$form); // Transfer default values in substitution entries. Return string finally...
    }
  }

  if ( $formtext == "" ) {  // Render it at least once.
    $formtext .= drupal_render($form);
    // Ask this question: Does this form now need to be stored? (Cache the form, put it into the DB.)
    if ( form_to_be_cached($form_id) ) {
      store_this_form($form_id,$formtext);
    }
  }

  $output .= $formtext;
  $output .= "\n</div>\n";

  return $output;
}



In order to make this code work, I made a new file to put in the include directory.
The file is attached, and it requires the following DB definition:

create table {forms} (
 	fid 	integer	 auto_increment
	form_id 	varchar(128),	
	dynamic 	tinyint(3) default 1, 	
	changed 	tinyint(3) default 1,
	formtext 	text,
	substitutions_keys 	varchar(255),
        PRIMARY KEY  (fid) 

An example of use is the following:

// TO and from the DB is required...
////

function copious_rolled_oats_content_registered_forms() {

  static $my_registered_forms = null;

  if ( $my_registered_forms == null ) {
    $formobj = drupal_fetch_form("copious_rolled_oats_content_admin_fields");
    if ( $formobj == null ) {
      $formvals = array();
      $formvals['dynamic'] = false;
      $formvals['changed'] = true;
      $formvals['formtext'] = "";
      $formvals['substitutions_keys'] = null;
      $formobj = (object)($formvals);
    }
    $my_registered_forms = array("copious_rolled_oats_content_admin_fields" => $formobj);
  } 

  return($my_registered_forms);
}



function copious_rolled_oats_content_store_registered_form($form_id,&$form_info) {

  if ( $form_id == "copious_rolled_oats_content_admin_fields" ) {
    $form_info->form_id = $form_id;
    $form_info->changed = false;
    drupal_store_form($form_id,$form_info);
  }
  
  return(null);
}

Oddly, this example works for a form that seems to be very dynamic. But, in truth, the form variability is determined by javascript parameters and not the actual form HTML.
So, as a result, even a highly dynamic form can be rendered just once. Of course, there are many lists, e.g. search results which require new forms every time.

dpearcefl’s picture

Is there any interest in this issue any longer?

If so, the need should be evaluated against D8.

Status: Active » Closed (outdated)

Automatically closed because Drupal 6 is no longer supported. If the issue verifiably applies to later versions, please reopen with details and update the version.