When building forms, the form_state['build_info']['files'] should contain all files that should be included for the form to work when it is cached.

When presently your try to execute a cached a block configuration form with a sub-module, such as menu_block, enabled, you will get the error 'Fatal error: Call to undefined function menu_block_configure_form_follow_validate() in /home/adrupal/www/includes/form.inc on line 1389'. I found that this was because menu_block defines its form builder and validators in the include file 'menu_block.admin.inc', which is logical and a good thing from the performance viewpoint. However, it does so by including it on-the-fly, as follows:

function menu_block_block_configure($delta = '') {
  module_load_include('inc', 'menu_block', 'menu_block.admin');
  return _menu_block_block_configure($delta);
}

I first thought this would be a bug in menu_block but the problem lies in block.module. It should provide a form_state, so that menu_block can add menu_block.admin.inc to form_state['build_info']['files']. Then, the error message won't appear when caching the form.

The solution is simple: extend the hook with a form state parameter.

/**
 * Define a configuration form for a block.
 *
 * @param $delta
 *   Which block is being configured. This is a unique identifier for the block
 *   within the module, defined in hook_block_info().
 * @param $form_state
 *   The form state of the form that the settings will be included in. You may
 *   have to use this, for example, when you use a include file. 
 *
 * @return
 *   A configuration form, if one is needed for your block beyond the standard
 *   elements that the block module provides (block title, visibility, etc.).
 *
 * For a detailed usage example, see block_example.module.
 *
 * @see hook_block_info()
 * @see hook_block_save()
 */
function hook_block_configure($delta = '', &$form_state) {
  // This example comes from node.module.
  $form = array();
  if ($delta == 'recent') {
    $form['node_recent_block_count'] = array(
      '#type' => 'select',
      '#title' => t('Number of recent content items to display'),
      '#default_value' => variable_get('node_recent_block_count', 10),
      '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 30)),
    );
  }
  return $form;
}
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

benjy’s picture

Is this still an issue?

The code around block and menu has vastly changed since this report.

bvanmeurs’s picture

Category: bug » feature
Priority: Normal » Minor

This is still an issue, as hook_block_configure does not have a form_state as the parameter. Because of this, it is still not possible to use include files in hook_block_configure.

However, I think this is more a feature request than a bug. It causes a bug when you try to implement the hook using an include file, as menu_block does, but is not a bug in itself.

That's why I change the status. The priority is minor as cached forms are not frequently used in practice.

swentel’s picture

Version: 8.x-dev » 7.x-dev

It's not relevant anymore though for D8 - blocks are now plugins and completely different (and the configure method passes by ref too btw)

swentel’s picture

Issue summary: View changes

.

joelpittet’s picture

Priority: Minor » Normal
Status: Active » Needs review
FileSize
1.5 KB

How about this? Would help us use form_load_include(). So that the callbacks could be outside the module.

function menu_block_block_configure($delta = '') {
  form_load_include('inc', 'menu_block', 'menu_block.admin');

  form_load_include($form_state, 'inc', 'menu_block', 'menu_block.admin');

Status: Needs review » Needs work

The last submitted patch, 4: 1596244-4.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

joelpittet’s picture

Status: Needs work » Needs review

Fluke fail

joelpittet’s picture