You are here

makemeeting.module in Make Meeting Scheduler 7.2

Same filename and directory in other branches
  1. 6 makemeeting.module
  2. 7 makemeeting.module

Hooks and field implementations

File

makemeeting.module
View source
<?php

/**
 * @file
 * Hooks and field implementations
 */

// Define choice constants
define('MAKEMEETING_ANSWER_PERM', 'answer makemeeting form');
define('MAKEMEETING_EDIT_PERM', 'edit any makemeeting answer');
define('MAKEMEETING_DELETE_PERM', 'delete any makemeeting answer');
define('MAKEMEETING_NO', 0);
define('MAKEMEETING_YES', 1);
define('MAKEMEETING_MAYBE', 2);

/**
 * Include required files.
 */
include_once 'makemeeting.field.inc';

/**
 * Implements hook_permission().
 */
function makemeeting_permission() {
  return array(
    MAKEMEETING_ANSWER_PERM => array(
      'title' => t('Provide an answer to makemeeting forms'),
      'description' => t('Give the ability to make a choice in makemeeting answer forms.'),
    ),
    MAKEMEETING_EDIT_PERM => array(
      'title' => t('Edit any makemeeting answers'),
      'description' => t('Edit answers given by other users.'),
    ),
    MAKEMEETING_DELETE_PERM => array(
      'title' => t('Delete any makemeeting answers'),
      'description' => t('Delete answers given by other users.'),
    ),
  );
}

/**
 * Implements hook_menu().
 */
function makemeeting_menu() {
  $items['makemeeting/delete-answer/%makemeeting_answer'] = array(
    'title' => 'Remove an answer',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'makemeeting_delete_answer',
      2,
    ),
    'access callback' => 'makemeeting_delete_answer_access',
    'access arguments' => array(
      2,
    ),
    'file' => 'makemeeting.pages.inc',
    'type' => MENU_CALLBACK,
  );
  $items['makemeeting/edit-answer/%makemeeting_answer'] = array(
    'title' => 'Edit an answer',
    'page callback' => 'makemeeting_edit_answer',
    'page arguments' => array(
      2,
    ),
    'access callback' => 'makemeeting_edit_answer_access',
    'access arguments' => array(
      2,
    ),
    'file' => 'makemeeting.pages.inc',
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Load an answer
 *
 * @param $answer_id
 * @return mixed
 */
function makemeeting_answer_load($answer_id) {
  $answer = db_select('makemeeting_answers', 'm')
    ->fields('m')
    ->condition('answer_id', $answer_id)
    ->execute()
    ->fetchAssoc();
  $answer['value'] = unserialize($answer['value']);
  return $answer ? (object) $answer : FALSE;
}

/**
 * Access callback: delete an answer
 *
 * @param $answer
 * @return bool
 */
function makemeeting_delete_answer_access($answer) {
  global $user;
  return user_access(MAKEMEETING_DELETE_PERM) || user_is_logged_in() && $answer->uid == $user->uid;
}

/**
 * Access callback: edit an answer
 *
 * @param $answer
 * @return bool
 */
function makemeeting_edit_answer_access($answer) {
  global $user;
  return user_access(MAKEMEETING_EDIT_PERM) || user_is_logged_in() && $answer->uid == $user->uid;
}

/**
 * Ajax callback in response to an answer that has been edited.
 *
 * This returns the new form content to replace the form content made obsolete
 * by the form submission.
 */
function makemeeting_answer_js($form, $form_state) {
  $values = $form_state['values'];
  $answer = $values['answer_edited'];
  $entities = entity_load($answer->entity_type, array(
    $answer->entity_id,
  ));
  if (empty($entities)) {
    return drupal_not_found();
  }
  $entity = $entities[$answer->entity_id];
  $field = $entity->{$answer->field_name}[$answer->language][$answer->delta];

  // We need to empty POST data to prevent the form
  // from being processed as submitted
  $_POST = array();
  $new_form = drupal_get_form('makemeeting_answers_form_' . $answer->entity_id, $field, $values);

  // AJaX processing overrides form action, now retrieving the correct one
  $query = parse_url($form['#action']);
  $parameters = drupal_get_query_array($query['query']);
  $new_form['#action'] = $parameters['destination'];
  return $new_form;
}

/**
 * Implements hook_forms().
 */
function makemeeting_forms($form_id) {
  $forms = array();
  if (preg_match('/^makemeeting_answers_form_\\d+?$/', $form_id)) {
    module_load_include('inc', 'makemeeting', 'makemeeting.form');
    $forms = array(
      $form_id => array(
        'callback' => 'makemeeting_answers_form',
      ),
    );
  }
  return $forms;
}

/**
 * Implements hook_theme().
 */
function makemeeting_theme($existing, $type, $theme, $path) {
  return array(
    'makemeeting_choices' => array(
      'render element' => 'form',
      'file' => 'makemeeting.theme.inc',
    ),
    'makemeeting_answers' => array(
      'render element' => 'form',
      'file' => 'makemeeting.theme.inc',
    ),
    'makemeeting_answer_row' => array(
      'render element' => 'form',
      'file' => 'makemeeting.theme.inc',
    ),
  );
}

/**
 * Helper function to convert date field value into an Unix timestamp
 *
 * @param $array array Date field value (month, day and year)
 * @return \DateTime
 */
function _makemeeting_date_timestamp($array) {
  $date_str = "{$array['day']}-{$array['month']}-{$array['year']}";
  return new DateTime($date_str);
}

/**
 * Helper function for selecting choices
 *
 * @param bool $three_choices If should be returning three choices
 * @return array An array of options for radios
 */
function _makemeeting_options($three_choices = FALSE) {
  $options = array(
    MAKEMEETING_NO => t('No'),
    MAKEMEETING_MAYBE => t('Maybe'),
    MAKEMEETING_YES => t('Yes'),
  );
  if (!$three_choices) {
    unset($options[MAKEMEETING_MAYBE]);
  }
  return $options;
}

/**
 * Invalidate related entity caches.
 *
 * Clear the core page cache and the contrib Entity Cache of the entity.
 *
 * @param $entity_type
 * @param $entity_id
 */
function _makemeeting_clear_related_entity_cache($entity_type, $entity_id) {

  // Clear entity_type cache.
  entity_get_controller($entity_type)
    ->resetCache();

  // Clear core page cache.
  if (variable_get('cache', FALSE)) {
    $entities = entity_load($entity_type, array(
      $entity_id,
    ));
    $entity = reset($entities);
    global $base_root;
    $uri = entity_uri($entity_type, $entity);

    // Clear the non-aliased page.
    cache_clear_all($base_root . base_path() . $uri['path'], 'cache_page');

    // Clear the aliased page.
    cache_clear_all(url($uri['path'], array(
      'absolute' => TRUE,
    )), 'cache_page');
  }

  // Clear referencing entities cache.
  if (module_exists('entityreference')) {
    _makemeeting_clear_referencing_entity_cache($entity_type, $entity_id);
  }
}

/**
 * Invalidate referencing entities caches.
 *
 * Recursive function clearing the cache for all the entities that references
 * the given one using the entityreference module.
 *
 * @param $entity_type
 * @param $entity_id
 */
function _makemeeting_clear_referencing_entity_cache($entity_type, $entity_id) {
  $cleared =& drupal_static(__FUNCTION__, array());

  // Avoid the cache to be cleared twice for the same entity.
  if (!empty($cleared[$entity_type][$entity_id])) {
    return;
  }
  $cleared[$entity_type][$entity_id] = TRUE;

  // Get the entity bundle to retreive the field that can reference this kind
  // of entities.
  $entity = entity_load_single($entity_type, $entity_id);
  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
  $fields_referencing = _makemeeting_clear_referencing_fields($entity_type, $bundle);

  // For each referencing field, get the entities that references the current
  // entity using the field and clear their cache.
  foreach ($fields_referencing as $field_name) {
    $query = new EntityFieldQuery();
    $query
      ->fieldCondition($field_name, 'target_id', $entity_id);
    foreach ($query
      ->execute() as $referent_entity_type => $referent_entities) {
      foreach ($referent_entities as $referent_entity_id => $referent_entity) {
        _makemeeting_clear_related_entity_cache($referent_entity_type, $referent_entity_id);
      }
    }
  }
}

/**
 * Get all fields referencing a given bundle.
 *
 * @param $entity_type
 *   The entity type of the bundle.
 * @param $bundle
 *   The referenced bundle.
 * @return array
 *   An array of field names being able to reference the given bundle.
 */
function _makemeeting_clear_referencing_fields($entity_type, $bundle) {
  $static =& drupal_static(__FUNCTION__, array());

  // Use a static temporary cache to avoid using too mush resources.
  if (array_key_exists($entity_type, $static) && array_key_exists($bundle, $static[$entity_type])) {
    return $static[$entity_type][$bundle];
  }
  $fields = field_info_fields();
  $static[$entity_type][$bundle] = array();
  foreach ($fields as $field_name => $field) {

    // Check if the field is an entityreference field.
    if ($field['type'] != 'entityreference') {
      continue;
    }

    // Check if the entity_type match the target_type of the field.
    if ($field['settings']['target_type'] != $entity_type) {
      continue;
    }

    // If the field is using the base handler check if the bundle is allowed.
    if ($field['settings']['handler'] == 'base' && !in_array($bundle, $field['settings']['handler_settings']['target_bundles'])) {
      continue;
    }
    $static[$entity_type][$bundle][] = $field_name;
  }
  return $static[$entity_type][$bundle];
}

/**
 * Implements hook_field_views_data_alter().
 */
function makemeeting_field_views_data_alter(&$result, $field, $module) {
  if ($module == 'makemeeting') {
    foreach ($result as $table => $data) {
      $field_name = $field['field_name'];

      // We will replace the filter handlers with a friendlier one.
      $result[$table][$field_name . '_closed']['filter']['handler'] = 'views_handler_filter_boolean_operator';
      $result[$table][$field_name . '_hidden']['filter']['handler'] = 'views_handler_filter_boolean_operator';
      $result[$table][$field_name . '_one_option']['filter']['handler'] = 'views_handler_filter_boolean_operator';
      $result[$table][$field_name . '_yesnomaybe']['filter']['handler'] = 'views_handler_filter_boolean_operator';
    }
  }
}

Functions

Namesort descending Description
makemeeting_answer_js Ajax callback in response to an answer that has been edited.
makemeeting_answer_load Load an answer
makemeeting_delete_answer_access Access callback: delete an answer
makemeeting_edit_answer_access Access callback: edit an answer
makemeeting_field_views_data_alter Implements hook_field_views_data_alter().
makemeeting_forms Implements hook_forms().
makemeeting_menu Implements hook_menu().
makemeeting_permission Implements hook_permission().
makemeeting_theme Implements hook_theme().
_makemeeting_clear_referencing_entity_cache Invalidate referencing entities caches.
_makemeeting_clear_referencing_fields Get all fields referencing a given bundle.
_makemeeting_clear_related_entity_cache Invalidate related entity caches.
_makemeeting_date_timestamp Helper function to convert date field value into an Unix timestamp
_makemeeting_options Helper function for selecting choices

Constants