You are here

ife.module in Inline Form Errors 7

Same filename and directory in other branches
  1. 6.2 ife.module
  2. 6 ife.module
  3. 7.2 ife.module

Drupal hooks

@author Stijn De Meyere

File

ife.module
View source
<?php

// $Id$

/**
 * @file
 * Drupal hooks
 *
 * @author Stijn De Meyere
 */

/**
 * Implements hook_menu().
 */
function ife_menu() {
  $items = array();
  $items['admin/config/user-interface/ife'] = array(
    'title' => 'Inline Form Errors',
    'description' => 'Administer which forms to use with field messages.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'ife_settings_form',
    ),
    'access arguments' => array(
      'administer inline form errors',
    ),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'ife.settings.inc',
  );
  $items['admin/config/user-interface/ife/%ife_form_id/delete'] = array(
    'title' => 'Delete form_id',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'ife_form_id_delete_form',
      3,
    ),
    'access arguments' => array(
      'administer inline form errors',
    ),
    'type' => MENU_CALLBACK,
    'file' => 'ife.settings.inc',
  );
  return $items;
}

/**
 * Implements hook_permission().
 */
function ife_permission() {
  return array(
    'administer inline form errors' => array(
      'title' => t('administer inline form errors'),
      'description' => t('TODO Add a description for \'administer inline form errors\''),
    ),
  );
}

/**
 * Implements hook_help().
 */
function ife_help($path, $arg) {
  switch ($path) {
    case 'admin/help#ife':
      $output = '<p>' . t('IFE or Inline Form Errors allows you to place form submission error inline with the form elements. Three options are provided for setting your inline error behaviour. You can configure the default behaviour or override the behaviour on a per form basis. You can add as many forms as you like.') . '</p>';
      $output .= '<p>' . t('IFE provides three behaviours for the configured forms') . '</p>';
      $output .= '<ul>';
      $output .= '<li>' . t('<strong>Leave the messages in place</strong>, this option will copy the error messages and place them inline. The original error messages set by Drupal will remain in place') . '</li>';
      $output .= '<li>' . t("<strong>Show an alternate message</strong>, this option will replace the original messages with a generic error message such as 'Please correct all errors.'. This message can be set in the IFE configuration page. The original error messages are placed inline with the form elements") . '</li>';
      $output .= '<li>' . t('<strong>Remove all messages</strong>, this option will remove all error messages and place them inline with the form element') . '</li>';
      $output .= '</ul>';
      $output .= '<p>' . t('In all cases only the messages related to the form will be touched. All other messages will remain in tact.') . '</p>';
      return $output;
    case 'admin/config/user-interface/ife':
      return '<p>' . t('This page provides the interface for adding new forms to use inline errors. Just add the form_id of the forms you wish to alter. An * can be used as a wildcard. The default settings can be overridden on a per form basis.') . '</p>';
  }
}

/**
 * Menu loader function to fetch a form id.
 */
function ife_form_id_load($form_id) {
  $form_ids = ife_load_form_ids();
  foreach ((array) $form_ids as $form_id_pattern => $form_settings) {
    if (ife_match_form_id($form_id, $form_id_pattern)) {
      return $form_settings;
    }
  }
  return FALSE;
}

/**
 * Check if a form ID pattern matches a given form ID.
 *
 * @param string $form_id
 *   The form ID to compare the pattern to.
 * @param string $form_id_pattern
 *   A form ID pattern. Ex. webform_*.
 *
 * @return boolean
 *   TRUE if the pattern matches the form_id, FALSE otherwise.
 */
function ife_match_form_id($form_id, $form_id_pattern) {

  // Convert form_id_pattern to a regular expression: replace /* with asterisks.
  $to_replace = array(
    '/\\\\\\*/',
  );
  $replacements = array(
    '.*',
  );

  // Quote regular expression characters.
  $form_id_pattern_quoted = preg_quote($form_id_pattern, '/');

  // Create regular expression.
  $form_id_pattern_regex = '/^(' . preg_replace($to_replace, $replacements, $form_id_pattern_quoted) . ')$/';
  return (bool) preg_match($form_id_pattern_regex, $form_id);
}

/**
 * Implements hook_theme().
 */
function ife_theme() {
  return array(
    'ife_settings_form_ids' => array(
      'render element' => 'form',
      'file' => 'ife.theme.inc',
    ),
    'ife_form_element' => array(
      'render element' => 'element',
      'file' => 'ife.theme.inc',
      'path' => drupal_get_path('module', 'ife'),
    ),
  );
}

/**
 *  Load all form ids from the data base
 */
function ife_load_form_ids() {
  static $ife_form_ids;
  if ($ife_form_ids) {
    $form_ids = $ife_form_ids;
  }
  else {
    $cache = cache_get('ife_form_ids', 'cache');
    if ($cache) {
      $form_ids = $cache->data;
    }
  }
  if (empty($form_ids)) {
    $result = db_select('ife')
      ->fields('ife', array(
      'form_id',
      'field_types',
      'status',
      'display',
    ))
      ->orderBy('form_id')
      ->execute();
    $form_ids = array();
    foreach ($result as $row) {
      $form_ids[$row->form_id] = $row;
    }
    cache_set('ife_form_ids', $form_ids, 'cache');
  }
  $ife_form_ids = $form_ids;
  return $ife_form_ids;
}

/**
 * Helper function to determine the display settings of a form
 */
function ife_form_id_display($form_id) {
  if ($form_id->display == -1) {
    $display = variable_get('ife_display', 1);
  }
  else {
    $display = $form_id->display;
  }
  return $display;
}

/**
 * Implements hook_form_alter().
 */
function ife_form_alter(&$form, $form_state, $form_id) {
  $ife_options = ife_form_id_load($form_id);
  if ($ife_options && $ife_options->status) {
    $display = ife_form_id_display($ife_options);
    ife_filter_form($form, $display);
    $form['#ife_display'] = $display;
    $form['#validate'][] = 'ife_form_validator';
    $form['#post_render'][] = 'ife_session_cleanup';
  }

  //print form_ids
  if (variable_get('ife_show_form_ids', 0)) {
    $form['ife_form_id'] = array(
      '#markup' => t('Form ID: @form_id', array(
        '@form_id' => $form_id,
      )),
      '#weight' => -1000,
      '#access' => user_access('administer inline form errors'),
    );
  }
}

/**
 * Function to set the general error mesage if set
 */
function ife_form_validator($form, &$form_state) {
  $form_errors = form_get_errors();
  if (!empty($form_errors)) {
    ife_element_get_error($form);
    if ($form['#ife_display'] == 1) {
      $message = filter_xss_admin(variable_get('ife_general_message', 'Please correct all highlighted errors and try again.'));
      drupal_set_message($message, 'error');
    }
  }
}

/**
 * Function to recursivly go through a form and alter all valid field type elements
 */
function ife_filter_form(&$form, $display) {

  //get all possible children
  $keys = element_children($form);
  $field_types = ife_field_types();
  foreach ($keys as $key) {
    $element_type = isset($form[$key]['#type']) ? $form[$key]['#type'] : FALSE;
    if (in_array($element_type, $field_types)) {
      ife_alter_form_element($form[$key], $display);
    }
    ife_filter_form($form[$key], $display);
  }
}

/**
 * Function to add our custom theme to the element
 */
function ife_alter_form_element(&$element, $display) {

  // Adding any theme wrappers here will mean the default ones don't get added-
  // so we get the default ones and add them first.
  $defaults = element_info_property($element['#type'], '#theme_wrappers');
  if (empty($element['#theme_wrappers']) && !empty($defaults)) {
    $element['#theme_wrappers'] = $defaults;
  }
  $element['#theme_wrappers'][] = 'ife_form_element';

  //resend the element type, drupal sets the #type marker to markup
  $element['#field_type'] = $element['#type'];

  //add display type to element to avoid extra queries
  $element['#display_type'] = $display;

  // These elements need special attention. Make sure that default pre-render
  // functions are included.
  switch ($element['#type']) {
    case 'text_format':
    case 'date_popup':
    case 'date_select':
    case 'date_text':
      $defaults = element_info_property($element['#type'], '#pre_render', array());
      if (empty($element['#pre_render'])) {
        $element['#pre_render'] = $defaults;
      }
      $element['#pre_render'] = array_merge($element['#pre_render'], array(
        'ife_text_format_prerender',
      ));
      break;
  }
}

/**
 * Pre render function for any elements that need special attention.
 */
function ife_text_format_prerender($element) {
  switch ($element['#type']) {
    case 'text_format':

      // Make sure that text_format sub-elements get filtered.
      ife_filter_form($element, $element['#display_type']);
      break;
    case 'date_popup':
    case 'date_select':
    case 'date_text':

      // Date's process functions unhelpfully replace the #theme_wrappers.
      $element['#theme_wrappers'][] = 'ife_form_element';
  }
  return $element;
}

/**
 * Function to determine all element errors on a given element.
 */
function ife_element_get_error($element, $debug = FALSE) {
  if (!isset($_SESSION['messages'])) {
    return;
  }

  // Recurse through all children.
  foreach (element_children($element) as $key) {
    if (isset($element[$key]) && $element[$key]) {
      ife_element_get_error($element[$key]);
    }
  }

  //check for errors and settings
  $errors = form_get_errors();
  $element_id = implode('][', $element['#parents']);
  if (!empty($errors[$element_id])) {
    $error_message = $errors[$element_id];

    //get error id
    $error_id = array_search($error_message, $_SESSION['messages']['error']);
    if ($error_id !== FALSE) {
      if (isset($element['#display_type']) && $element['#display_type'] != 0) {
        unset($_SESSION['messages']['error'][$error_id]);
        $_SESSION['messages']['error'] = array_values($_SESSION['messages']['error']);
      }
      if (count($_SESSION['messages']['error']) <= 0) {
        unset($_SESSION['messages']['error']);
      }

      // Set error message in session, so it can be used in our theming.
      $_SESSION['ife'][$element['#id']] = $error_message;
    }
  }
}

/**
 * Clear the session after the form has been build.
 */
function ife_session_cleanup($form, $form_state) {
  if (isset($_SESSION['ife'])) {
    unset($_SESSION['ife']);
  }
  return $form;
}

/**
 * Helper function that identifies the different field types default in drupal
 */
function ife_field_types() {
  $expandable = ife_expandable_field_types();
  $extra = array(
    'checkbox',
    'file',
    'link',
    'machine_name',
    'managed_file',
    'password',
    'radio',
    'select',
    'textarea',
    'textfield',
    'weight',
  );
  return array_merge($expandable, $extra);
}

/**
 * Helper function that identifies the different expandable field types default in drupal
 */
function ife_expandable_field_types() {
  $core = array(
    'checkboxes',
    'date',
    'password_confirm',
    'radios',
    'text_format',
  );
  $contrib = array(
    // Date
    'date_combo',
    'date_popup',
    'date_repeat_rrule',
    'date_select',
    'date_text',
    'date_timezone',
    // Link
    'link_field',
    // Webform
    'webform_time',
    'webform_grid',
  );
  return array_merge($core, $contrib);
}

Functions

Namesort descending Description
ife_alter_form_element Function to add our custom theme to the element
ife_element_get_error Function to determine all element errors on a given element.
ife_expandable_field_types Helper function that identifies the different expandable field types default in drupal
ife_field_types Helper function that identifies the different field types default in drupal
ife_filter_form Function to recursivly go through a form and alter all valid field type elements
ife_form_alter Implements hook_form_alter().
ife_form_id_display Helper function to determine the display settings of a form
ife_form_id_load Menu loader function to fetch a form id.
ife_form_validator Function to set the general error mesage if set
ife_help Implements hook_help().
ife_load_form_ids Load all form ids from the data base
ife_match_form_id Check if a form ID pattern matches a given form ID.
ife_menu Implements hook_menu().
ife_permission Implements hook_permission().
ife_session_cleanup Clear the session after the form has been build.
ife_text_format_prerender Pre render function for any elements that need special attention.
ife_theme Implements hook_theme().