Sometimes when building an advanced Drupal form that involves form_alter plus including files you will encounters problems that Drupal is complaining about a missing functions that is in your include file.

This problem usualy happen if your form submit function utilizes $form_state['rebuild'] = TRUE or invoked via ajax. Drupal form system is smart enough to auto load all of your include files if you call it using module_load_include() function, or form_load_include() function.

Sometimes when building an advanced Drupal form that involves form_alter plus including files you will encounters problems that Drupal is complaining about a missing functions that is in your include file.

This problem usualy happen if your form submit function utilizes $form_state['rebuild'] = TRUE or invoked via ajax. Drupal form system is smart enough to auto load all of your include files if you call it using module_load_include() function, or form_load_include() function.

We can examine the actual code that load the include files: Example form_load_include() function :

function form_load_include(&$form_state, $type, $module, $name = NULL) { 
  if (!isset($name)) { 
    $name = $module; 
  } 

  if (!isset($form_state['build_info']['files']["$module:$name.$type"])) { 
    
    // Only add successfully included files to the form state. 
    if ($result =  module_load_include($type, $module, $name)) { 
      $form_state['build_info']['files']["$module:$name.$type"] = array(
         'type' => $type, 
         'module' => $module, 'name' => $name, 
      ); 
      return $result; 
    } 
  }
 
  return FALSE; 
}

 

As we can see the function will fetch information about the files from $form_state['build_info'] and load the file using module_load_include() function.

Now the major problem with this function is if your include files is not actualy from a module or theme, but it reside in other directory such as sites/all/libraries folder?

If we examine the actual code that do the loading for extra include files, in form.inc :


/**
 * Fetches a form from cache.
 */
function form_get_cache($form_build_id, &$form_state) {
  if ($cached = cache_get('form_' . $form_build_id, 'cache_form')) {
    $form = $cached->data;

    global $user;

    if ((isset($form['#cache_token']) && drupal_valid_token($form['#cache_token'])) || (!isset($form['#cache_token']) && !$user->uid)) {
      	
      if ($cached = cache_get('form_state_' . $form_build_id, 'cache_form')) {

        // Re-populate $form_state for subsequent rebuilds.
        $form_state = $cached->data + $form_state;

        // If the original form is contained in include files, load the files.
        // @see form_load_include()
        $form_state['build_info'] += array(
            'files' => array()
        );

        foreach ($form_state['build_info']['files'] as $file) {
          if (is_array($file)) {
            $file += array(
                'type' => 'inc',
                'name' => $file['module']
            );

            module_load_include($file['type'], $file['module'], $file['name']);
          }
          elseif (file_exists($file)) {

            require_once DRUPAL_ROOT . '/' . $file;
          }
        }
      }
      	
      return $form;
    }
  }
}

You can see the function will parse the $form_state['build_info'] and test if the entry there is an array (thus invoking module_load_include() function) or just plain require_once() if the entry is not an array.

Now basing from the function, we can easily force Drupal to load extra include file by adding entry to $form_state['build_info'] manually.

For example

$file = 'sites/all/libraries/mycool_include_files.inc'; 

if (!isset($form_state['build_info']['files'][$file])) { 
  if (is_file($file)) { 
    require_once $file; $form_state['build_info']['files'][$file] = $file; 
  } 
}

Then now every time form is rebuilding or fetched via ajax, the include files will automatically loaded by Drupal.

We can also create a function for this so it can be reusable for different form :

 

/** 
  * Simple function to load include files, 
  * This will be helpful if the files is not a theme or module files 
  */
function vtcore_form_load_includes($file, $form, &$form_state) { 
  if (empty($file)) { 
    return FALSE; 
  } 

  if (!isset($form_state['build_info']['files'][$file])) { 
    if (is_file($file)) { 
      require_once $file; 
      $form_state['build_info']['files'][$file] = $file; 
    } 
  } 

  if (isset($form_state['build_info']['files'][$file])) { 
    return TRUE; 
  } 
}

Now you can just invoke the function by specifying the file url as $file and pass the $form and $form_state from your form;