You are here

bat_calendar_reference.module in Booking and Availability Management Tools for Drupal 7

Same filename and directory in other branches
  1. 8 modules/bat_calendar_reference/bat_calendar_reference.module

Defines a field type for referencing event information.

File

modules/bat_calendar_reference/bat_calendar_reference.module
View source
<?php

/**
 * @file
 * Defines a field type for referencing event information.
 */

/**
 * Implements hook_permission().
 */
function bat_calendar_reference_permission() {
  $permissions = array(
    'reference unit calendar events' => array(
      'title' => t('Reference unit calendar events'),
      'description' => t('Allows users to embed events information in other nodes.'),
    ),
  );
  return $permissions;
}

/**
 * Implements hook_menu().
 */
function bat_calendar_reference_menu() {
  $items['bat_calendar_reference/autocomplete/units/%/%/%'] = array(
    'page callback' => 'bat_calendar_reference_units_autocomplete',
    'page arguments' => array(
      3,
      4,
      5,
    ),
    'access arguments' => array(
      'reference unit calendar events',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['bat_calendar_reference/autocomplete/unit_types/%/%/%'] = array(
    'page callback' => 'bat_calendar_reference_unit_types_autocomplete',
    'page arguments' => array(
      3,
      4,
      5,
    ),
    'access arguments' => array(
      'reference unit calendar events',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['bat_calendar_reference/autocomplete/event_types/%/%/%'] = array(
    'page callback' => 'bat_calendar_reference_event_types_autocomplete',
    'page arguments' => array(
      3,
      4,
      5,
    ),
    'access arguments' => array(
      'reference unit calendar events',
    ),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implements hook_field_info().
 */
function bat_calendar_reference_field_info() {
  return array(
    'bat_calendar_unit_reference' => array(
      'label' => t('BAT Calendar Unit Reference'),
      'description' => t('Display unit events information embedded from other fieldable content.'),
      'settings' => array(
        'referenceable_unit_types' => array(),
      ),
      'default_widget' => 'bat_calendar_reference_unit_autocomplete',
      'default_formatter' => 'bat_calendar_reference_timeline_view',
    ),
    'bat_calendar_unit_type_reference' => array(
      'label' => t('BAT Calendar Unit Type Reference'),
      'description' => t('Display unit type events information embedded from other fieldable content.'),
      'settings' => array(),
      'default_widget' => 'bat_calendar_reference_unit_type_autocomplete',
      'default_formatter' => 'bat_calendar_reference_timeline_view',
    ),
  );
}

/**
 * Implements hook_field_is_empty().
 */
function bat_calendar_reference_field_is_empty($item, $field) {
  if ($field['type'] == 'bat_calendar_unit_reference') {
    return empty($item['unit_id']);
  }
  elseif ($field['type'] == 'bat_calendar_unit_type_reference') {
    return empty($item['unit_type_id']);
  }
}

/**
 * Implements hook_field_formatter_info().
 */
function bat_calendar_reference_field_formatter_info() {
  $ret = array(
    'bat_calendar_reference_month_view' => array(
      'label' => t('Month View'),
      'description' => t('Displays event information on a calendar.'),
      'field types' => array(
        'bat_calendar_unit_reference',
        'bat_calendar_unit_type_reference',
        'entityreference',
      ),
    ),
    'bat_calendar_reference_timeline_view' => array(
      'label' => t('Timeline View'),
      'description' => t('Displays event information on a calendar.'),
      'field types' => array(
        'bat_calendar_unit_reference',
        'bat_calendar_unit_type_reference',
        'entityreference',
      ),
    ),
  );
  return $ret;
}

/**
 * Implements hook_field_formatter_prepare_view().
 */
function bat_calendar_reference_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
  if ($field['type'] == 'entityreference') {
    entityreference_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, $items, $displays);
  }
}

/**
 * Implements hook_field_formatter_view().
 */
function bat_calendar_reference_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  $fc_user_settings = array();
  $header = '';
  $calendar_id = drupal_html_id($field['field_name'] . '-calendar-formatter');
  switch ($display['type']) {
    case 'bat_calendar_reference_timeline_view':
    case 'bat_calendar_reference_month_view':
      if ($field['type'] == 'bat_calendar_unit_type_reference') {
        $unit_type_names = array();
        $unit_type_ids = array();
        foreach ($items as $delta => $item) {
          if ($unit_type = bat_type_load($item['unit_type_id'])) {
            $unit_type_names[] = $unit_type->name;
            $unit_type_ids[] = $unit_type->type_id;
          }
          if ($type = bat_event_type_load($item['event_type_id'])) {
            $event_type = $type->type;
            $event_granularity = $type->event_granularity;
          }
        }
        if (!empty($unit_type_ids)) {
          $header = '<div class="calendar-title"><h2>' . implode(', ', $unit_type_names) . '</h2></div>';

          // Inject settings in javascript that we will use.
          $fc_user_settings[$calendar_id] = array(
            'unitTypes' => $unit_type_ids,
            'unitIDs' => '',
            'eventType' => $event_type,
            'calendar_id' => 'fullcalendar-scheduler',
            'modal_style' => 'default',
            'eventGranularity' => $event_granularity,
            'editable' => FALSE,
            'selectable' => FALSE,
            'eventStartEditable' => FALSE,
            'background' => '1',
          );
          if ($display['type'] == 'bat_calendar_reference_month_view') {
            $fc_user_settings[$calendar_id]['defaultView'] = 'month';
            $fc_user_settings[$calendar_id]['views'] = 'month';
            $fc_user_settings[$calendar_id]['background'] = '0';
            $fc_user_settings[$calendar_id]['headerLeft'] = 'today';
            $fc_user_settings[$calendar_id]['headerCenter'] = 'title';
            $fc_user_settings[$calendar_id]['headerRight'] = 'prev, next';
          }
        }
      }
      elseif ($field['type'] == 'bat_calendar_unit_reference') {
        $unit_names = array();
        $unit_ids = array();
        foreach ($items as $delta => $item) {
          if ($unit = bat_unit_load($item['unit_id'])) {
            $unit_names[] = $unit->name;
            $unit_ids[] = $unit->unit_id;
          }
          if ($type = bat_event_type_load($item['event_type_id'])) {
            $event_type = $type->type;
            $event_granularity = $type->event_granularity;
          }
        }
        if (!empty($unit_ids)) {
          $header = '<div class="calendar-title"><h2>' . implode(', ', $unit_names) . '</h2></div>';

          // Inject settings in javascript that we will use.
          $fc_user_settings[$calendar_id] = array(
            'unitTypes' => 'all',
            'unitIDs' => $unit_ids,
            'eventType' => $event_type,
            'calendar_id' => 'fullcalendar-scheduler',
            'modal_style' => 'default',
            'eventGranularity' => $event_granularity,
            'editable' => FALSE,
            'selectable' => FALSE,
            'eventStartEditable' => FALSE,
            'background' => '1',
          );
          if ($display['type'] == 'bat_calendar_reference_month_view') {
            $fc_user_settings[$calendar_id]['defaultView'] = 'month';
            $fc_user_settings[$calendar_id]['views'] = 'month';
            $fc_user_settings[$calendar_id]['background'] = '0';
            $fc_user_settings[$calendar_id]['headerLeft'] = 'today';
            $fc_user_settings[$calendar_id]['headerCenter'] = 'title';
            $fc_user_settings[$calendar_id]['headerRight'] = 'prev, next';
          }
        }
      }
      break;
  }
  if (!empty($fc_user_settings)) {
    $calendar_settings = array(
      'modal_style' => 'default',
      'calendar_id' => 'fullcalendar-scheduler',
      'user_settings' => array(
        'batCalendar' => $fc_user_settings,
      ),
    );
    $element[] = array(
      '#theme' => 'bat_fullcalendar',
      '#calendar_settings' => $calendar_settings,
      '#js_files' => array(
        drupal_get_path('module', 'bat_calendar_reference') . '/js/bat_calendar_reference.js',
      ),
      '#css_files' => array(
        drupal_get_path('module', 'bat_fullcalendar') . '/css/bat_fullcalendar_timeline.css',
        drupal_get_path('module', 'bat_fullcalendar') . '/css/fullcalendar.theme.css',
      ),
      '#attributes' => array(
        'id' => $calendar_id,
        'class' => array(
          'cal',
          'clearfix',
        ),
      ),
      '#prefix' => $header,
    );
  }
  return $element;
}

/**
 * Implements hook_field_settings_form().
 */
function bat_calendar_reference_field_settings_form($field, $instance, $has_data) {
  $settings = $field['settings'];
  $form = array();
  if ($field['type'] == 'bat_calendar_unit_reference') {
    $form['referenceable_unit_types'] = array(
      '#type' => 'checkboxes',
      '#title' => t('Unit types that can be referenced'),
      '#multiple' => TRUE,
      '#default_value' => isset($settings['referenceable_unit_types']) ? $settings['referenceable_unit_types'] : array(),
      '#options' => array_map('check_plain', bat_unit_types_ids()),
    );
  }
  $form['referenceable_event_types'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Event types that can be referenced'),
    '#multiple' => TRUE,
    '#default_value' => isset($settings['referenceable_event_types']) ? $settings['referenceable_event_types'] : array(),
    '#options' => array_map('check_plain', bat_event_types_ids()),
  );
  return $form;
}

/**
 * Implements hook_field_validate().
 */
function bat_calendar_reference_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {

  // Check for non-numeric values.
  foreach ($items as $delta => $item) {
    if (is_array($item)) {
      if (!empty($item['unit_id'])) {
        if (!is_numeric($item['unit_id'])) {
          $errors[$field['field_name']][$langcode][$delta][] = array(
            'error' => 'invalid_unit',
            'message' => t('%name: invalid input.', array(
              '%name' => $instance['label'],
            )),
          );
        }
      }
      if (!empty($item['unit_type_id'])) {
        if (!is_numeric($item['unit_type_id'])) {
          $errors[$field['field_name']][$langcode][$delta][] = array(
            'error' => 'invalid_unit_type',
            'message' => t('%name: invalid input.', array(
              '%name' => $instance['label'],
            )),
          );
        }
      }
      if (!empty($item['event_type_id'])) {
        if (!is_numeric($item['event_type_id'])) {
          $errors[$field['field_name']][$langcode][$delta][] = array(
            'error' => 'invalid_event_type',
            'message' => t('%name: invalid input.', array(
              '%name' => $instance['label'],
            )),
          );
        }
      }
    }
  }
}

/**
 * Retrieves an array of candidate referenceable booking units.
 *
 * @param array $field
 *   The field definition.
 * @param array $options
 *   An array of options to limit the scope of the returned list. The following
 *   key/value pairs are accepted:
 *   - string: string to filter unit names on (used by autocomplete).
 *   - match: operator to match the above string against, can be any of:
 *     'contains', 'equals', 'starts_with'. Defaults to 'contains'.
 *   - ids: array of specific unit ids to lookup.
 *   - limit: maximum size of the the result set. Defaults to 0 (no limit).
 *
 * @return array
 *   An array of valid units in the form:
 *   array(
 *     unit_id => array(
 *       'name' => The unit title,
 *       'rendered' => The text to display in widgets (can be HTML)
 *     ),
 *     ...
 *   )
 */
function bat_calendar_reference_units_potential_references($field, $options = array()) {

  // Fill in default options.
  $options += array(
    'string' => '',
    'match' => 'contains',
    'ids' => array(),
    'limit' => 0,
  );
  $results =& drupal_static(__FUNCTION__, array());

  // Create unique id for static cache.
  $cid = $field['field_name'] . ':' . $options['match'] . ':' . ($options['string'] !== '' ? $options['string'] : implode('-', $options['ids'])) . ':' . $options['limit'];
  if (!isset($results[$cid])) {
    $references = FALSE;
    if ($references === FALSE) {
      $references = _bat_calendar_reference_units_potential_references($field, $options);
    }

    // Store the results.
    $results[$cid] = !empty($references) ? $references : array();
  }
  return $results[$cid];
}

/**
 * @param array $field
 * @param array $options
 *
 * @return array
 */
function _bat_calendar_reference_units_potential_references($field, $options) {

  // Avoid useless work.
  if (!isset($field['settings']['referenceable_unit_types'])) {
    return array();
  }
  if (!count($field['settings']['referenceable_unit_types'])) {
    return array();
  }
  $query = db_select('bat_units', 'u');
  $unit_unit_id_alias = $query
    ->addField('u', 'unit_id');
  $unit_name_alias = $query
    ->addField('u', 'name', 'name');
  $unit_type_alias = $query
    ->addField('u', 'type', 'type');
  if (is_array($field['settings']['referenceable_unit_types'])) {
    $referenceable_unit_types = array_filter($field['settings']['referenceable_unit_types']);
    if (!empty($referenceable_unit_types)) {
      $query
        ->condition('u.type_id', array_filter($field['settings']['referenceable_unit_types']), 'IN');
    }
  }
  if ($options['string'] !== '') {
    switch ($options['match']) {
      case 'contains':
        $query
          ->condition('u.name', '%' . $options['string'] . '%', 'LIKE');
        break;
      case 'starts_with':
        $query
          ->condition('u.name', $options['string'] . '%', 'LIKE');
        break;
      case 'equals':
      default:

        // No match type or incorrect match type: use "=".
        $query
          ->condition('u.name', $options['string']);
        break;
    }
  }
  if ($options['ids']) {
    $query
      ->condition('u.unit_id', $options['ids'], 'IN');
  }
  if ($options['limit']) {
    $query
      ->range(0, $options['limit']);
  }
  $query
    ->orderBy($unit_name_alias)
    ->orderBy($unit_type_alias);
  $result = $query
    ->execute()
    ->fetchAll();
  $references = array();
  foreach ($result as $unit) {
    $references[$unit->unit_id] = array(
      'title' => $unit->name,
      'rendered' => check_plain($unit->name),
    );
  }
  return $references;
}

/**
 * @param array $field
 * @param array $options
 *
 * @return array
 */
function bat_calendar_reference_event_types_potential_references($field, $options = array()) {

  // Fill in default options.
  $options += array(
    'string' => '',
    'match' => 'contains',
    'ids' => array(),
    'limit' => 0,
  );
  $results =& drupal_static(__FUNCTION__, array());

  // Create unique id for static cache.
  $cid = $field['field_name'] . ':' . $options['match'] . ':' . ($options['string'] !== '' ? $options['string'] : implode('-', $options['ids'])) . ':' . $options['limit'];
  if (!isset($results[$cid])) {
    $references = FALSE;
    if ($references === FALSE) {
      $references = _bat_calendar_reference_event_types_potential_references($field, $options);
    }

    // Store the results.
    $results[$cid] = !empty($references) ? $references : array();
  }
  return $results[$cid];
}

/**
 * @param array $field
 * @param array $options
 *
 * @return array
 */
function _bat_calendar_reference_event_types_potential_references($field, $options) {

  // Avoid useless work.
  if (!isset($field['settings']['referenceable_event_types'])) {
    return array();
  }
  if (!count($field['settings']['referenceable_event_types'])) {
    return array();
  }
  $query = db_select('bat_event_type', 'u');
  $unit_unit_id_alias = $query
    ->addField('u', 'id');
  $event_type_label_alias = $query
    ->addField('u', 'label', 'label');
  if (is_array($field['settings']['referenceable_event_types'])) {
    $referenceable_event_types = array_filter($field['settings']['referenceable_event_types']);
    if (!empty($referenceable_event_types)) {
      $query
        ->condition('u.id', array_filter($field['settings']['referenceable_event_types']), 'IN');
    }
  }
  if ($options['string'] !== '') {
    switch ($options['match']) {
      case 'contains':
        $query
          ->condition('u.label', '%' . $options['string'] . '%', 'LIKE');
        break;
      case 'starts_with':
        $query
          ->condition('u.label', $options['string'] . '%', 'LIKE');
        break;
      case 'equals':
      default:

        // No match type or incorrect match type: use "=".
        $query
          ->condition('u.label', $options['string']);
        break;
    }
  }
  if ($options['limit']) {
    $query
      ->range(0, $options['limit']);
  }
  $query
    ->orderBy($event_type_label_alias);
  $result = $query
    ->execute()
    ->fetchAll();
  $references = array();
  foreach ($result as $event_type) {
    $references[$event_type->id] = array(
      'title' => $event_type->label,
      'rendered' => check_plain($event_type->label),
    );
  }
  return $references;
}

/**
 * @param array $field
 * @param array $options
 *
 * @return array
 */
function bat_calendar_reference_unit_types_potential_references($field, $options = array()) {

  // Fill in default options.
  $options += array(
    'string' => '',
    'match' => 'contains',
    'ids' => array(),
    'limit' => 0,
  );
  $results =& drupal_static(__FUNCTION__, array());

  // Create unique id for static cache.
  $cid = $field['field_name'] . ':' . $options['match'] . ':' . ($options['string'] !== '' ? $options['string'] : implode('-', $options['ids'])) . ':' . $options['limit'];
  if (!isset($results[$cid])) {
    $references = FALSE;
    if ($references === FALSE) {
      $references = _bat_calendar_reference_unit_types_potential_references($field, $options);
    }

    // Store the results.
    $results[$cid] = !empty($references) ? $references : array();
  }
  return $results[$cid];
}

/**
 * @param array $field
 * @param array $options
 *
 * @return array
 */
function _bat_calendar_reference_unit_types_potential_references($field, $options) {
  $query = db_select('bat_types', 'u');
  $unit_unit_id_alias = $query
    ->addField('u', 'type_id');
  $type_name_alias = $query
    ->addField('u', 'name', 'name');
  if ($options['string'] !== '') {
    switch ($options['match']) {
      case 'contains':
        $query
          ->condition('u.name', '%' . $options['string'] . '%', 'LIKE');
        break;
      case 'starts_with':
        $query
          ->condition('u.name', $options['string'] . '%', 'LIKE');
        break;
      case 'equals':
      default:

        // No match type or incorrect match type: use "=".
        $query
          ->condition('u.name', $options['string']);
        break;
    }
  }
  if ($options['limit']) {
    $query
      ->range(0, $options['limit']);
  }
  $query
    ->orderBy($type_name_alias);
  $result = $query
    ->execute()
    ->fetchAll();
  $references = array();
  foreach ($result as $unit_type) {
    $references[$unit_type->type_id] = array(
      'title' => $unit_type->name,
      'rendered' => check_plain($unit_type->name),
    );
  }
  return $references;
}

/**
 * Menu callback for the units autocomplete results.
 */
function bat_calendar_reference_units_autocomplete($entity_type, $bundle, $field_name, $string = '') {
  $field = field_info_field($field_name);
  $instance = field_info_instance($entity_type, $field_name, $bundle);
  $options = array(
    'string' => $string,
    'match' => $instance['widget']['settings']['autocomplete_match'],
    'limit' => 10,
  );
  $references = bat_calendar_reference_units_potential_references($field, $options);
  $matches = array();
  foreach ($references as $id => $row) {

    // Markup is fine in autocompletion results (might happen when rendered
    // through Views) but we want to remove hyperlinks.
    $suggestion = preg_replace('/<a href="([^<]*)">([^<]*)<\\/a>/', '$2', $row['rendered']);

    // Add a class wrapper for a few required CSS overrides.
    $matches[$row['title'] . " [unit_id:{$id}]"] = '<div class="reference-autocomplete">' . $suggestion . '</div>';
  }
  drupal_json_output($matches);
}

/**
 * Menu callback for the unit types autocomplete results.
 */
function bat_calendar_reference_unit_types_autocomplete($entity_type, $bundle, $field_name, $string = '') {
  $field = field_info_field($field_name);
  $instance = field_info_instance($entity_type, $field_name, $bundle);
  $options = array(
    'string' => $string,
    'match' => $instance['widget']['settings']['autocomplete_match'],
    'limit' => 10,
  );
  $references = bat_calendar_reference_unit_types_potential_references($field, $options);
  $matches = array();
  foreach ($references as $id => $row) {

    // Markup is fine in autocompletion results (might happen when rendered
    // through Views) but we want to remove hyperlinks.
    $suggestion = preg_replace('/<a href="([^<]*)">([^<]*)<\\/a>/', '$2', $row['rendered']);

    // Add a class wrapper for a few required CSS overrides.
    $matches[$row['title'] . " [type_id:{$id}]"] = '<div class="reference-autocomplete">' . $suggestion . '</div>';
  }
  drupal_json_output($matches);
}

/**
 * Menu callback for the event types autocomplete results.
 */
function bat_calendar_reference_event_types_autocomplete($entity_type, $bundle, $field_name, $string = '') {
  $field = field_info_field($field_name);
  $instance = field_info_instance($entity_type, $field_name, $bundle);
  $options = array(
    'string' => $string,
    'match' => $instance['widget']['settings']['autocomplete_match'],
    'limit' => 10,
  );
  $references = bat_calendar_reference_event_types_potential_references($field, $options);
  $matches = array();
  foreach ($references as $id => $row) {

    // Markup is fine in autocompletion results (might happen when rendered
    // through Views) but we want to remove hyperlinks.
    $suggestion = preg_replace('/<a href="([^<]*)">([^<]*)<\\/a>/', '$2', $row['rendered']);

    // Add a class wrapper for a few required CSS overrides.
    $matches[$row['title'] . " [event_type_id:{$id}]"] = '<div class="reference-autocomplete">' . $suggestion . '</div>';
  }
  drupal_json_output($matches);
}

/**
 * Implements hook_field_widget_info().
 */
function bat_calendar_reference_field_widget_info() {
  return array(
    'bat_calendar_reference_unit_autocomplete' => array(
      'label' => t('Calendar Unit reference'),
      'description' => t('Display the list of referenceable units and event types as a textfield with autocomplete behaviour.'),
      'field types' => array(
        'bat_calendar_unit_reference',
      ),
      'settings' => array(
        'autocomplete_match' => 'contains',
      ),
    ),
    'bat_calendar_reference_unit_type_autocomplete' => array(
      'label' => t('Calendar Unit type reference'),
      'description' => t('Display the list of referenceable units and event types as a textfield with autocomplete behaviour.'),
      'field types' => array(
        'bat_calendar_unit_type_reference',
      ),
      'settings' => array(
        'autocomplete_match' => 'contains',
      ),
    ),
  );
}

/**
 * Implements hook_field_widget_form().
 */
function bat_calendar_reference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  $widget = array(
    '#theme_wrappers' => array(
      'container',
      'form_element',
    ),
    '#attributes' => array(
      'class' => array(
        'container-inline',
      ),
    ),
  );
  switch ($instance['widget']['type']) {
    case 'bat_calendar_reference_unit_autocomplete':
      $widget['unit_id'] = array(
        '#type' => 'textfield',
        '#title' => t('Unit'),
        '#default_value' => isset($items[$delta]['unit_id']) ? $items[$delta]['unit_id'] : NULL,
        '#autocomplete_path' => 'bat_calendar_reference/autocomplete/units/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/' . $field['field_name'],
        '#size' => 60,
        '#maxlength' => 255,
        '#element_validate' => array(
          'bat_calendar_reference_autocomplete_unit_validate',
        ),
        '#value_callback' => 'bat_calendar_reference_unit_autocomplete_value',
      );
      $widget['event_type_id'] = array(
        '#type' => 'textfield',
        '#title' => t('Event type'),
        '#default_value' => isset($items[$delta]['event_type_id']) ? $items[$delta]['event_type_id'] : NULL,
        '#autocomplete_path' => 'bat_calendar_reference/autocomplete/event_types/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/' . $field['field_name'],
        '#size' => 60,
        '#maxlength' => 255,
        '#element_validate' => array(
          'bat_calendar_reference_autocomplete_event_type_validate',
        ),
        '#value_callback' => 'bat_calendar_reference_event_type_autocomplete_value',
      );
      break;
    case 'bat_calendar_reference_unit_type_autocomplete':
      $widget['unit_type_id'] = array(
        '#type' => 'textfield',
        '#title' => t('Unit type'),
        '#default_value' => isset($items[$delta]['unit_type_id']) ? $items[$delta]['unit_type_id'] : NULL,
        '#autocomplete_path' => 'bat_calendar_reference/autocomplete/unit_types/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/' . $field['field_name'],
        '#size' => 60,
        '#maxlength' => 255,
        '#element_validate' => array(
          'bat_calendar_reference_autocomplete_unit_type_validate',
        ),
        '#value_callback' => 'bat_calendar_reference_unit_type_autocomplete_value',
      );
      $widget['event_type_id'] = array(
        '#type' => 'textfield',
        '#title' => t('Event type'),
        '#default_value' => isset($items[$delta]['event_type_id']) ? $items[$delta]['event_type_id'] : NULL,
        '#autocomplete_path' => 'bat_calendar_reference/autocomplete/event_types/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/' . $field['field_name'],
        '#size' => 60,
        '#maxlength' => 255,
        '#element_validate' => array(
          'bat_calendar_reference_autocomplete_event_type_validate',
        ),
        '#value_callback' => 'bat_calendar_reference_event_type_autocomplete_value',
      );
      break;
  }
  return $element + $widget;
}

/**
 * Value callback for a bat_calendar_reference autocomplete element.
 *
 * Replace the unit id with a unit name.
 */
function bat_calendar_reference_unit_autocomplete_value($element, $input = FALSE, $form_state = array()) {
  if ($input === FALSE) {
    $unit_id = $element['#default_value'];
    if (!empty($unit_id)) {
      if ($unit = bat_unit_load($unit_id)) {
        $value = $unit->name;
        $value .= ' [unit_id:' . $unit_id . ']';
        return $value;
      }
      else {
        return '';
      }
    }
  }
}

/**
 * Value callback for a bat_calendar_reference autocomplete element.
 *
 * Replace the unit type id with a unit type name.
 */
function bat_calendar_reference_unit_type_autocomplete_value($element, $input = FALSE, $form_state = array()) {
  if ($input === FALSE) {
    $type_id = $element['#default_value'];
    if (!empty($type_id)) {
      if ($unit_type = bat_type_load($type_id)) {
        $value = $unit_type->name;
        $value .= ' [type_id:' . $type_id . ']';
        return $value;
      }
      else {
        return '';
      }
    }
  }
}

/**
 * Value callback for a bat_calendar_reference autocomplete element.
 *
 * Replace the event type id with a event type label.
 */
function bat_calendar_reference_event_type_autocomplete_value($element, $input = FALSE, $form_state = array()) {
  if ($input === FALSE) {
    $event_type = $element['#default_value'];
    if (!empty($event_type)) {
      if ($type = bat_event_type_load($event_type)) {
        $value = $type->label;
        $value .= ' [event_type_id:' . $event_type . ']';
        return $value;
      }
      else {
        return '';
      }
    }
  }
}

/**
 * Validate unit.
 */
function bat_calendar_reference_autocomplete_unit_validate($element, &$form_state, $form) {
  $parents = $element['#array_parents'];
  array_pop($parents);
  $field_widget = drupal_array_get_nested_value($form, $parents);
  $field = field_widget_field($field_widget, $form_state);
  $instance = field_widget_instance($field_widget, $form_state);
  $value = $element['#value'];
  $unit_id = NULL;
  if (!empty($value)) {

    // Check whether we have an explicit "[unit_id:n]" input.
    preg_match('/^(?:\\s*|(.*) )?\\[\\s*unit_id\\s*:\\s*(\\d+)\\s*\\]$/', $value, $matches);
    if (!empty($matches)) {
      list(, $title, $unit_id) = $matches;
      if (!empty($title)) {
        $unit = bat_unit_load($unit_id);
        $real_title = $unit->name;
        if (trim($title) != trim($real_title)) {
          form_error($element, t('%name: title mismatch. Please check your selection.', array(
            '%name' => $instance['label'],
          )));
        }
      }
    }
    else {
      $options = array(
        'string' => $value,
        'match' => 'equals',
        'limit' => 1,
      );
      $references = bat_calendar_reference_units_potential_references($field, $options);
      if ($references) {
        $unit_id = key($references);
      }
      else {
        form_error($element, t('%name: unable to find a unit with that title.', array(
          '%name' => $instance['label'],
        )));
      }
    }
  }
  form_set_value($element, $unit_id, $form_state);
}

/**
 * Validate unit type.
 */
function bat_calendar_reference_autocomplete_unit_type_validate($element, &$form_state, $form) {
  $parents = $element['#array_parents'];
  array_pop($parents);
  $field_widget = drupal_array_get_nested_value($form, $parents);
  $field = field_widget_field($field_widget, $form_state);
  $instance = field_widget_instance($field_widget, $form_state);
  $value = $element['#value'];
  $type_id = NULL;
  if (!empty($value)) {

    // Check whether we have an explicit "[type_id:n]" input.
    preg_match('/^(?:\\s*|(.*) )?\\[\\s*type_id\\s*:\\s*(\\d+)\\s*\\]$/', $value, $matches);
    if (!empty($matches)) {
      list(, $title, $type_id) = $matches;
      if (!empty($title)) {
        $unit = bat_type_load($type_id);
        $real_title = $unit->name;
        if (trim($title) != trim($real_title)) {
          form_error($element, t('%name: title mismatch. Please check your selection.', array(
            '%name' => $instance['label'],
          )));
        }
      }
    }
    else {
      $options = array(
        'string' => $value,
        'match' => 'equals',
        'limit' => 1,
      );
      $references = bat_calendar_reference_unit_types_potential_references($field, $options);
      if ($references) {
        $unit_id = key($references);
      }
      else {
        form_error($element, t('%name: unable to find a unit type with that title.', array(
          '%name' => $instance['label'],
        )));
      }
    }
  }
  form_set_value($element, $type_id, $form_state);
}

/**
 * Validate event type.
 */
function bat_calendar_reference_autocomplete_event_type_validate($element, &$form_state, $form) {
  $parents = $element['#array_parents'];
  array_pop($parents);
  $field_widget = drupal_array_get_nested_value($form, $parents);
  $field = field_widget_field($field_widget, $form_state);
  $instance = field_widget_instance($field_widget, $form_state);
  $value = $element['#value'];
  $type_id = NULL;
  if (!empty($value)) {

    // Check whether we have an explicit "[event_type_id:n]" input.
    preg_match('/^(?:\\s*|(.*) )?\\[\\s*event_type_id\\s*:\\s*(\\d+)\\s*\\]$/', $value, $matches);
    if (!empty($matches)) {
      list(, $title, $type_id) = $matches;
      if (!empty($title)) {
        $event_type = bat_event_type_load($type_id);
        $real_title = $event_type->label;
        if (trim($title) != trim($real_title)) {
          form_error($element, t('%name: title mismatch. Please check your selection.', array(
            '%name' => $instance['label'],
          )));
        }
      }
    }
    else {
      $options = array(
        'string' => $value,
        'match' => 'equals',
        'limit' => 1,
      );
      $references = bat_calendar_reference_event_types_potential_references($field, $options);
      if ($references) {
        $type_id = key($references);
      }
      else {
        form_error($element, t('%name: unable to find an event type with that title.', array(
          '%name' => $instance['label'],
        )));
      }
    }
  }
  form_set_value($element, $type_id, $form_state);
}

/**
 * Implements hook_field_widget_error().
 */
function bat_calendar_reference_field_widget_error($element, $error, $form, &$form_state) {
  form_error($element['unit_id'], $error['message']);
}

Functions

Namesort descending Description
bat_calendar_reference_autocomplete_event_type_validate Validate event type.
bat_calendar_reference_autocomplete_unit_type_validate Validate unit type.
bat_calendar_reference_autocomplete_unit_validate Validate unit.
bat_calendar_reference_event_types_autocomplete Menu callback for the event types autocomplete results.
bat_calendar_reference_event_types_potential_references
bat_calendar_reference_event_type_autocomplete_value Value callback for a bat_calendar_reference autocomplete element.
bat_calendar_reference_field_formatter_info Implements hook_field_formatter_info().
bat_calendar_reference_field_formatter_prepare_view Implements hook_field_formatter_prepare_view().
bat_calendar_reference_field_formatter_view Implements hook_field_formatter_view().
bat_calendar_reference_field_info Implements hook_field_info().
bat_calendar_reference_field_is_empty Implements hook_field_is_empty().
bat_calendar_reference_field_settings_form Implements hook_field_settings_form().
bat_calendar_reference_field_validate Implements hook_field_validate().
bat_calendar_reference_field_widget_error Implements hook_field_widget_error().
bat_calendar_reference_field_widget_form Implements hook_field_widget_form().
bat_calendar_reference_field_widget_info Implements hook_field_widget_info().
bat_calendar_reference_menu Implements hook_menu().
bat_calendar_reference_permission Implements hook_permission().
bat_calendar_reference_units_autocomplete Menu callback for the units autocomplete results.
bat_calendar_reference_units_potential_references Retrieves an array of candidate referenceable booking units.
bat_calendar_reference_unit_autocomplete_value Value callback for a bat_calendar_reference autocomplete element.
bat_calendar_reference_unit_types_autocomplete Menu callback for the unit types autocomplete results.
bat_calendar_reference_unit_types_potential_references
bat_calendar_reference_unit_type_autocomplete_value Value callback for a bat_calendar_reference autocomplete element.
_bat_calendar_reference_event_types_potential_references
_bat_calendar_reference_units_potential_references
_bat_calendar_reference_unit_types_potential_references