You are here

required_by_role.module in Required by role 7

Same filename and directory in other branches
  1. 8 required_by_role.module
  2. 7.2 required_by_role.module

File

required_by_role.module
View source
<?php

/**
 * @file
 * Allows certain user roles to be exempt from required fields
 */
module_load_include('inc', 'required_by_role', 'required_by_role.date');

/**
 * Implements hook_help().
 */
function required_by_role_help($path, $arg) {
  switch ($path) {
    case 'admin/help#required_by_role':
      $output = '';
      $output .= '<p>' . t('The Required by role module provides an easy and flexible way for developers and site builders to determine whether a field (instance) should be <em>required</em> by all users or just for selected user roles.') . '</p>';
      return $output;
  }
}

/**
 * Implements hook_field_info_alter().
 */
function required_by_role_field_info_alter(&$info) {
  foreach ($info as $field_type => $field_type_info) {
    $info[$field_type]['instance_settings'] += array(
      'required_by_role' => array(),
    );
  }
}

/**
 * Implements hook_field_widget_form_alter().
 */
function required_by_role_field_widget_form_alter(&$element, &$form_state, $context) {
  if (!$context['instance']['required']) {
    global $user;
    $account = $user;
    $settings = $context['instance']['settings'];

    // Getting the value based on our rules and some contextual information.
    $is_required = required_by_role_is_required($account, $settings, $context, $form_state);

    // We dediced to back to search manually the "#required" property.
    // Obviously it is not the best solution and it needs work but the option of
    // recreate the element was not  feasible as it was done because the are
    // running into infinite loops in field_default_form and
    // field_multiple_value_form as long the hook_field_widget_properties_alter
    // is not allowing us to modify the $context property and after is late to
    // act on a non "deployed" element.
    //
    _required_by_role_set_property($element, $is_required, $context, $form_state);

    // Give the opportunity to other modules to act on this property.
    drupal_alter('required_property', $element, $field, $is_required);
  }
}

/**
 * Helper function to set the #required property to a given element.
 *
 * @see form_builder
 */
function _required_by_role_set_property(&$element, $is_required, $context, $form_state) {
  if ($context['delta'] === 0) {

    // 0 based widgets.
    if (isset($element[0]['#required'])) {
      $element =& $element[0];
    }

    // "Value" based widgets.
    if (isset($element['value']['#required'])) {
      $element =& $element['value'];
    }

    // "[0][value]" based widgets.
    if (isset($element[0]['value']['#required'])) {
      $element =& $element[0]['value'];
    }

    // "[email]" based widgets.
    if (isset($element['email']['#required'])) {
      $element =& $element['email'];
    }
    $element['#required'] = $is_required;

    // Select element type has some behaviours regarding to the #required
    // property so we must apply the core process function here.
    if ($element['#type'] == 'select') {
      $element = form_process_select($element);
    }
  }
}

/**
 * Central method to figure out if the fields should be required or not based on the current callback.
 */
function required_by_role_is_required($account, $settings, $context, $form_state) {
  $is_required = NULL;
  $roles = $settings['required_by_role'] ? $settings['required_by_role'] : array();
  $required_callback = _required_by_role_get_callback();
  if (is_callable($required_callback)) {
    $is_required = $required_callback($account, $roles, $context, $form_state);
  }
  return $is_required;
}

/**
 * Helper function to get the callback.
 */
function _required_by_role_get_callback() {
  $required_callback = module_invoke('required_by_role', 'required_by_role_callback');

  // We give here the opportunity to change the callback function.
  drupal_alter('required_by_role_callback', $required_callback);
  return $required_callback;
}

/**
 * Implements hook_required_by_role_callback.
 * @return string
 *   Callback function to determine if the field is required or not
 */
function required_by_role_required_by_role_callback() {
  return '_required_by_role_roles_intersect';
}

/**
 * At least one of $roles values is in the $account->roles array?.
 */
function _required_by_role_roles_intersect($account, $roles, $context, $form_state) {
  $match = array_intersect(array_keys($account->roles), $roles);
  $is_required = !empty($match);
  return $is_required;
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function required_by_role_form_field_ui_field_edit_form_alter(&$form, $form_state) {
  $field_name = $form['#field']['field_name'];
  $required_by_role = $form['#instance']['settings']['required_by_role'];
  $label = t('Required by role');
  $description = t('Select this option if you want this field to be required for ALL ROLES, otherwise choose specific roles in the checkboxes, below, under %name', array(
    '%name' => 'Required by role',
  ));
  $roles = user_roles();
  unset($roles[DRUPAL_AUTHENTICATED_RID]);
  $header = array(
    'name' => t('Role'),
  );
  foreach ($roles as $rid => $role) {
    $options[$rid] = array(
      'name' => $role,
    );
  }
  $module_path = drupal_get_path('module', 'required_by_role');

  // Js add, needed because STATES API behaves unproperly
  // in this context hidding required option.
  $attached = array(
    'js' => array(
      $module_path . '/required_by_role.js',
    ),
  );
  $form['instance']['settings']['required_by_role'] = array(
    '#prefix' => '<label>' . $label . '</label>',
    '#type' => 'tableselect',
    '#header' => $header,
    '#options' => $options,
    '#default_value' => $required_by_role,
    '#weight' => $form['instance']['required']['#weight'] + 1,
    '#attached' => $attached,
    '#empty' => t('No roles available.'),
    '#attributes' => array(
      'class' => array(
        'tableselect-required-by-role',
      ),
    ),
  );
  $form['instance']['required']['#description'] = $description;

  // Default value needs always to be NOT required.
  $default_value_widget =& $form['instance']['default_value_widget'][$field_name][LANGUAGE_NONE];
  if (isset($default_value_widget[0]['#required'])) {
    $default_value_widget[0]['#required'] = FALSE;
  }
  else {
    $default_value_widget['#required'] = FALSE;
  }
  if (isset($default_value_widget[0]['value']['#required'])) {
    $default_value_widget[0]['value']['#required'] = FALSE;
  }
}

Functions

Namesort descending Description
required_by_role_field_info_alter Implements hook_field_info_alter().
required_by_role_field_widget_form_alter Implements hook_field_widget_form_alter().
required_by_role_form_field_ui_field_edit_form_alter Implements hook_form_FORM_ID_alter().
required_by_role_help Implements hook_help().
required_by_role_is_required Central method to figure out if the fields should be required or not based on the current callback.
required_by_role_required_by_role_callback Implements hook_required_by_role_callback.
_required_by_role_get_callback Helper function to get the callback.
_required_by_role_roles_intersect At least one of $roles values is in the $account->roles array?.
_required_by_role_set_property Helper function to set the #required property to a given element.