You are here

redhen_contact.module in RedHen CRM 7

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

Module file for RedHen contacts.

File

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

/**
 * @file
 * Module file for RedHen contacts.
 */

/**
 * Define variable names for RedHen contact settings.
 */
define('REDHEN_CONTACT_ALTER_USERNAME', 'redhen_contact_alter_username');
define('REDHEN_CONTACT_ALTER_COMMENT_AUTHOR', 'redhen_contact_alter_comments');
define('REDHEN_CONTACT_CONNECT_USERS', 'redhen_contact_connect_users');
define('REDHEN_CONTACT_MIRROR_EMAIL', 'redhen_contact_mirror_email');
define('REDHEN_CONTACT_REQUIRE_EMAIL', 'redhen_contact_require_email');
define('REDHEN_CONTACT_EMBED_ON_USER_FORM', 'redhen_contact_embed_on_user_form');
define('REDHEN_CONTACT_USER_EMAIL_TYPE', 'redhen_contact_user_email_type');
define('REDHEN_CONTACT_REQUIRE_FIRST_NAME', 'redhen_contact_require_first_name');
define('REDHEN_CONTACT_REG', 'redhen_contact_reg');
define('REDHEN_CONTACT_REG_TYPE', 'redhen_contact_reg_type');
define('REDHEN_CONTACT_REG_UPDATE', 'redhen_contact_reg_update');
define('REDHEN_CONTACT_REG_UPDATE_FIELDS', 'redhen_contact_reg_update_fields');
define('REDHEN_CONTACT_DELETE_USER_WITH_CONTACT', 'redhen_contact_delete_user_with_contact');

// View mode to render contact as on the user view page.
// Not configurable via the UI.
define('REDHEN_CONTACT_USER_VIEW_MODE', 'redhen_contact_user_view_mode');

/**
 * Implements hook_entity_info().
 */
function redhen_contact_entity_info() {
  return array(
    'redhen_contact' => array(
      'label' => t('Contact'),
      'plural label' => t('Contacts'),
      'controller class' => 'RedhenContactEntityController',
      'metadata controller class' => 'RedhenContactMetadataController',
      'rules controller class' => 'EntityDefaultRulesController',
      'entity class' => 'RedhenContact',
      'views controller class' => 'RedhenContactViewsController',
      'inline entity form' => array(
        'controller' => 'RedHenContactInlineEntityFormController',
      ),
      'base table' => 'redhen_contact',
      'revision table' => 'redhen_contact_revision',
      'fieldable' => TRUE,
      'entity keys' => array(
        'id' => 'contact_id',
        'revision' => 'revision_id',
        'bundle' => 'type',
      ),
      'bundle keys' => array(
        'bundle' => 'name',
      ),
      'bundles' => array(),
      'view modes' => array(
        'full' => array(
          'label' => t('Full contact'),
          'custom settings' => FALSE,
        ),
        'teaser' => array(
          'label' => t('Teaser'),
          'custom settings' => TRUE,
        ),
      ),
      'uri callback' => 'entity_class_uri',
      'token type' => 'redhen_contact',
      'module' => 'redhen_contact',
      'label callback' => 'entity_class_label',
      'access callback' => 'redhen_contact_access',
    ),
    'redhen_contact_type' => array(
      'label' => t('Contact type'),
      'entity class' => 'RedhenContactType',
      'controller class' => 'RedhenContactTypeController',
      'base table' => 'redhen_contact_type',
      'fieldable' => FALSE,
      'bundle of' => 'redhen_contact',
      'exportable' => TRUE,
      'token type' => 'redhen_contact_type',
      'entity keys' => array(
        'id' => 'contact_type_id',
        'name' => 'name',
        'label' => 'label',
      ),
      'access callback' => 'redhen_contact_type_access',
      'module' => 'redhen_contact',
      // Enable the entity API's admin UI.
      'admin ui' => array(
        'path' => 'admin/structure/redhen/contact_types',
        'file' => 'redhen_contact_type.admin.inc',
        'file path' => drupal_get_path('module', 'redhen_contact') . '/includes',
        'controller class' => 'RedhenContactTypeUIController',
      ),
    ),
  );
}

/**
 * Implements hook_entity_info_alter().
 *
 * We are adding the info about the contact types via a hook to avoid a
 * recursion issue as loading the model types requires the entity info as well.
 */
function redhen_contact_entity_info_alter(&$entity_info) {

  // @todo: Testing to ensure the schema exists; needed because running gui
  // install profile was hitting this BEFORE the schema was installed.
  if (drupal_get_schema('redhen_contact')) {
    foreach (redhen_contact_get_types() as $type => $info) {
      $entity_info['redhen_contact']['bundles'][$type] = array(
        'label' => $info->label,
        'admin' => array(
          'path' => 'admin/structure/redhen/contact_types/manage/%redhen_contact_type',
          'real path' => 'admin/structure/redhen/contact_types/manage/' . $type,
          'bundle argument' => 5,
          'access arguments' => array(
            'administer redhen_contact types',
          ),
        ),
      );
    }
  }
}

/**
 * Implements hook_entity_property_info_alter().
 */
function redhen_contact_entity_property_info_alter(&$info) {
  $info['user']['properties']['redhen_contact'] = array(
    'label' => "redhen_contact",
    'description' => "Points to the RedHen Contact entity connected to this user.",
    'getter callback' => 'redhen_contact_load_by_user_callback',
    'type' => 'redhen_contact',
  );
}

/**
 * Wrapper around redhen_contact_load_by_user to use as user property callback.
 */
function redhen_contact_load_by_user_callback($user, array $options, $property_name, $entity_type) {
  return redhen_contact_load_by_user($user);
}

/**
 * Implements hook_menu().
 */
function redhen_contact_menu() {
  $items = array();

  // Add a contact.
  $items['redhen/contact'] = array(
    'title' => 'Contacts',
    'description' => 'View RedHen CRM contacts.',
    'page callback' => 'redhen_contact_page',
    'file' => 'includes/redhen_contact.pages.inc',
    'access arguments' => array(
      'access redhen contacts',
    ),
  );

  // Add a contact.
  $items['redhen/contact/add'] = array(
    'title' => 'Add a contact',
    'description' => 'Add a new contact.',
    'page callback' => 'redhen_contact_types_list_page',
    'access callback' => 'redhen_contact_access',
    'access arguments' => array(
      'create',
    ),
    'file' => 'includes/redhen_contact.pages.inc',
    'type' => MENU_NORMAL_ITEM,
  );
  $entity_info = entity_get_info('redhen_contact');
  foreach ($entity_info['bundles'] as $key => $bundle) {
    $items['redhen/contact/add/' . $key] = array(
      'title' => $bundle['label'],
      'title callback' => 'check_plain',
      'description' => isset($bundle['description']) ? $bundle['description'] : '',
      'page callback' => 'redhen_contact_add_page',
      'page arguments' => array(
        $key,
      ),
      'access callback' => 'redhen_contact_access',
      'access arguments' => array(
        'create',
      ),
      'file' => 'includes/redhen_contact.pages.inc',
    );
  }
  $items['redhen/contact/%redhen_contact'] = array(
    'title callback' => 'redhen_contact_contact_title',
    'title arguments' => array(
      2,
    ),
    'page callback' => 'redhen_contact_view',
    'page arguments' => array(
      2,
    ),
    'access callback' => 'redhen_contact_access',
    'access arguments' => array(
      'view',
      2,
    ),
    'weight' => 10,
  );
  $items['redhen/contact/%redhen_contact/view'] = array(
    'title' => 'Summary',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
  );
  $items['redhen/contact/%redhen_contact/view/view'] = array(
    'title' => 'View',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => 1,
  );
  $items['redhen/contact/%redhen_contact/view/edit'] = array(
    'title' => 'Edit',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'redhen_contact_contact_form',
      2,
    ),
    'access callback' => 'redhen_contact_access',
    'access arguments' => array(
      'edit',
      2,
    ),
    'type' => MENU_LOCAL_TASK,
    'file' => 'includes/redhen_contact.forms.inc',
    'weight' => 2,
  );
  $items['redhen/contact/%redhen_contact/view/user'] = array(
    'title' => 'Drupal user',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'redhen_contact_contact_user_form',
      2,
    ),
    'access callback' => 'redhen_contact_access',
    'access arguments' => array(
      'edit',
      2,
    ),
    'type' => MENU_LOCAL_TASK,
    'file' => 'includes/redhen_contact.forms.inc',
    'weight' => 3,
  );
  $items['redhen/contact/%redhen_contact/view/delete'] = array(
    'title' => 'Delete',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'redhen_contact_contact_delete_form',
      2,
    ),
    'access callback' => 'redhen_contact_access',
    'access arguments' => array(
      'delete',
      2,
    ),
    'type' => MENU_LOCAL_TASK,
    'file' => 'includes/redhen_contact.forms.inc',
    'weight' => 5,
  );
  $items['redhen/contact/%redhen_contact/view/archive'] = array(
    'title' => 'Archive',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'redhen_contact_contact_archive_form',
      2,
    ),
    'access callback' => 'redhen_contact_access',
    'access arguments' => array(
      'archive',
      2,
    ),
    'type' => MENU_LOCAL_TASK,
    'file' => 'includes/redhen_contact.forms.inc',
    'weight' => 4,
  );
  $items['redhen/contact/%redhen_contact/revisions'] = array(
    'title' => 'Revisions',
    'type' => MENU_LOCAL_TASK,
    'page callback' => 'redhen_contact_revision_list',
    'page arguments' => array(
      2,
    ),
    'access callback' => 'user_access',
    'access arguments' => array(
      'view redhen contact revisions',
    ),
    'file' => 'includes/redhen_contact.pages.inc',
    'weight' => 4,
  );
  $items['redhen/contact/%redhen_contact/revisions/%redhen_contact_revision'] = array(
    'title callback' => 'redhen_contact_contact_title',
    'title arguments' => array(
      4,
    ),
    'page callback' => 'redhen_contact_view',
    'page arguments' => array(
      4,
    ),
    'access callback' => 'redhen_contact_access',
    'access arguments' => array(
      'view',
      4,
    ),
  );
  $items['redhen/contact/%redhen_contact/revisions/%redhen_contact_revision/view'] = array(
    'title' => 'Summary',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
  );
  $items['redhen/contact/%redhen_contact/revisions/%redhen_contact_revision/edit'] = array(
    'title' => 'Edit',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'redhen_contact_contact_form',
      4,
    ),
    'access callback' => 'redhen_contact_access',
    'access arguments' => array(
      'edit',
      4,
    ),
    'type' => MENU_LOCAL_TASK,
    'file' => 'includes/redhen_contact.forms.inc',
    'weight' => 2,
  );
  $items['redhen/contact/%redhen_contact/revisions/%redhen_contact_revision/delete'] = array(
    'title' => 'Delete',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'redhen_contact_contact_delete_form',
      4,
    ),
    'access callback' => 'redhen_contact_access',
    'access arguments' => array(
      'delete',
      4,
    ),
    'type' => MENU_LOCAL_TASK,
    'file' => 'includes/redhen_contact.forms.inc',
    'weight' => 5,
  );
  $items['redhen/contact/%redhen_contact/view/unarchive'] = array(
    'title' => 'Unarchive',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'redhen_contact_contact_unarchive_form',
      2,
    ),
    'access callback' => 'redhen_contact_access',
    'access arguments' => array(
      'unarchive',
      2,
    ),
    'type' => MENU_LOCAL_TASK,
    'file' => 'includes/redhen_contact.forms.inc',
    'weight' => 4,
  );
  if (!variable_get(REDHEN_CONTACT_EMBED_ON_USER_FORM, FALSE)) {
    $items['user/%user/redhen_contact'] = array(
      'title' => 'RedHen Contact',
      'page callback' => 'drupal_get_form',
      'page arguments' => array(
        'redhen_contact_user_contact_form',
        1,
      ),
      'access callback' => 'redhen_contact_user_contact_access',
      'access arguments' => array(
        1,
      ),
      'type' => MENU_LOCAL_TASK,
      'file' => 'includes/redhen_contact.forms.inc',
      'weight' => 5,
    );
  }
  if (module_exists('devel')) {
    $items['redhen/contact/%redhen_contact/devel'] = array(
      'title' => 'Devel',
      'page callback' => 'redhen_devel_load_object',
      'page arguments' => array(
        'redhen_contact',
        2,
      ),
      'access arguments' => array(
        'access devel information',
      ),
      'type' => MENU_LOCAL_TASK,
      'weight' => 100,
    );
    $items['redhen/contact/%redhen_contact/devel/load'] = array(
      'title' => 'Load',
      'type' => MENU_DEFAULT_LOCAL_TASK,
    );
    $items['redhen/contact/%redhen_contact/devel/render'] = array(
      'title' => 'Render',
      'page callback' => 'redhen_devel_render_object',
      'page arguments' => array(
        'redhen_contact',
        2,
      ),
      'access arguments' => array(
        'access devel information',
      ),
      'type' => MENU_LOCAL_TASK,
      'weight' => 100,
    );
  }
  return $items;
}

/**
 * Implements hook_menu_local_tasks_alter().
 *
 * Changing the redhen/contact/add menu item to type MENU_LOCAL_ACTION would
 * break display of child items. Instead, dynamically add the local action.
 */
function redhen_contact_menu_local_tasks_alter(&$data, $router_item, $root_path) {

  // Add action link to 'redhen/contact/add' on 'redhen/contact' page.
  if ($root_path == 'redhen/contact') {
    $item = menu_get_item('redhen/contact/add');
    if ($item['access']) {
      $data['actions']['output'][] = array(
        '#theme' => 'menu_local_action',
        '#link' => $item,
      );
    }
  }
}

/**
 * Implements hook_theme().
 */
function redhen_contact_theme() {
  return array(
    'redhen_contact_add_list' => array(
      'variables' => array(
        'content' => NULL,
      ),
    ),
    'redhen_contact_list' => array(
      'variables' => array(
        'contacts' => NULL,
        'header' => NULL,
        'rows' => NULL,
      ),
    ),
  );
}

/**
 * Loads a contact by ID.
 */
function redhen_contact_load($contact_id) {
  if (empty($contact_id)) {
    return FALSE;
  }
  $contacts = redhen_contact_load_multiple(array(
    $contact_id,
  ), array());
  return $contacts ? reset($contacts) : FALSE;
}

/**
 * Loads multiple contacts by ID or based on a set of matching conditions.
 *
 * @param array $contact_ids
 *   An array of contact IDs.
 * @param array $conditions
 *   An array of conditions on the {redhen_contact} table in the form
 *     'field' => $value.
 * @param bool $reset
 *   Whether to reset the internal contact loading cache.
 *
 * @see entity_load()
 *
 * @return array
 *   An array of contact objects indexed by contact_id.
 */
function redhen_contact_load_multiple($contact_ids = array(), $conditions = array(), $reset = FALSE) {
  if (empty($contact_ids) && empty($conditions)) {
    return array();
  }
  return entity_load('redhen_contact', $contact_ids, $conditions, $reset);
}

/**
 * Loads a contact revision by ID.
 */
function redhen_contact_revision_load($revision_id) {
  if (empty($revision_id)) {
    return FALSE;
  }
  return entity_revision_load('redhen_contact', $revision_id);
}

/**
 * Deletes multiple contacts by ID.
 *
 * @param array $contact_ids
 *   An array of contact IDs to delete.
 *
 * @return array
 *   TRUE on success, FALSE otherwise.
 */
function redhen_contact_delete_multiple($contact_ids) {
  $ret = entity_get_controller('redhen_contact')
    ->delete($contact_ids);
  return $ret;
}

/**
 * Saves a contact.
 *
 * @param RedhenContact $contact
 *   The full contact object to save.
 *
 * @return RedhenContact
 *   The saved contact object.
 */
function redhen_contact_save(RedhenContact $contact) {
  $contact
    ->save();
  return $contact;
}

/**
 * Checks contact access for various operations.
 *
 * @param string $op
 *   The operation being performed. One of 'view', 'update', 'create' or
 *   'delete'.
 * @param RedhenContact|string $contact
 *   Contact to check access for, or for the create operation, the contact type.
 *   If nothing is given access permissions for all contacts are returned.
 * @param object $account
 *   The user to check for. Leave it to NULL to check for the current user.
 */
function redhen_contact_access($op, $contact = NULL, $account = NULL) {

  // Map 'update' to 'edit' which is used internally below.
  $op = $op == 'update' ? 'edit' : $op;
  global $user;
  $redhen_relation_role_permissions = module_exists('redhen_relation') ? redhen_relation_role_get_permissions($user) : array();
  $account = isset($account) ? $account : $user;
  $related_orgs = $contact && module_exists('redhen_relation') ? redhen_relation_relations($contact, REDHEN_RELATION_AFFILIATION, TRUE) : array();
  if ($op == 'archive' && $contact->redhen_state == REDHEN_STATE_ARCHIVED) {
    return FALSE;
  }
  if ($op == 'unarchive' && $contact->redhen_state == REDHEN_STATE_ACTIVE) {
    return FALSE;
  }
  if (user_access('administer redhen contacts', $account)) {
    return TRUE;
  }

  // Set $default_revision as a shortcut variable to check, because relation
  // role permissions do not currently support revisions.
  if (is_object($contact) && $contact
    ->isDefaultRevision()) {
    $default_revision = TRUE;
  }
  else {
    $default_revision = FALSE;
  }
  switch ($op) {
    case 'view':
      if ($default_revision) {

        // Regular and relation role checks.
        if (user_access('access redhen contacts', $account)) {
          return TRUE;
        }

        // Check whether user can view own contact.
        if (user_access('view own redhen contact', $account) && $contact->uid == $user->uid) {
          return TRUE;
        }
        foreach ($related_orgs as $org) {
          if (isset($redhen_relation_role_permissions[$org[0]->org_id])) {
            return TRUE;
          }
        }
      }
      else {

        // Revision checks. Relation role permissions do not support revisions.
        if (user_access('view redhen contact revisions', $account)) {
          return TRUE;
        }
      }
      break;
    case 'archive':
    case 'unarchive':

      // We have already checked the op against the current state. Just check
      // the permissions.
      if (user_access('manage redhen contacts', $account)) {
        return TRUE;
      }
      break;
    case 'edit':
      if ($default_revision) {

        // Regular and relations role checks.
        if (user_access('manage redhen contacts', $account)) {
          return TRUE;
        }
        foreach ($related_orgs as $org) {
          if (isset($redhen_relation_role_permissions[$org[0]->org_id]['edit_contact']) && $redhen_relation_role_permissions[$org[0]->org_id]['edit_contact'] !== 0) {
            return TRUE;
          }
        }
      }
      else {

        // Revision checks. Relation role permissions do not support revisions.
        if (user_access('edit redhen contact revisions', $account)) {
          return TRUE;
        }
      }
      break;
    case 'delete':
      if ($default_revision) {

        // Regular and relations role checks.
        if (user_access('manage redhen contacts', $account)) {
          return TRUE;
        }
        foreach ($related_orgs as $org) {
          if (isset($redhen_relation_role_permissions[$org[0]->org_id]['delete_contact']) && $redhen_relation_role_permissions[$org[0]->org_id]['delete_contact'] !== 0) {
            return TRUE;
          }
        }
      }
      else {

        // Revision checks. Relation role permissions do not support revisions.
        if (user_access('manage redhen contacts', $account)) {
          return TRUE;
        }
      }
      break;
    case 'create':
      if (user_access('manage redhen contacts', $account)) {
        return TRUE;
      }
      if (isset($contact) && is_string($contact)) {
        if (user_access('create ' . $contact . ' contacts', $account)) {
          return TRUE;
        }
      }
      break;
  }
  return FALSE;
}

/**
 * Implements hook_permission().
 */
function redhen_contact_permission() {
  return array(
    'administer redhen_contact types' => array(
      'title' => t('Administer RedHen Contact Types'),
      'description' => t('Manage RedHen contact types and their structure.'),
    ),
    'administer redhen contacts' => array(
      'title' => t('Administer RedHen Contacts'),
      'description' => t('Perform administration tasks for RedHen Contacts.'),
    ),
    'manage redhen contacts' => array(
      'title' => t('Manage RedHen Contacts'),
      'description' => t('Create, update or delete RedHen Contacts.'),
    ),
    'access redhen contacts' => array(
      'title' => t('Access Redhen Contacts'),
      'description' => t('View RedHen Contacts.'),
    ),
    'view own redhen contact' => array(
      'title' => t('Access Own Redhen Contact.'),
      'description' => t('View your own contact information.'),
    ),
    'edit own redhen contact' => array(
      'title' => t('Edit Own Redhen Contact.'),
      'description' => t('Edit your own contact information.'),
    ),
    'view redhen contact revisions' => array(
      'title' => t('View Redhen Contact revisions'),
    ),
    'edit redhen contact revisions' => array(
      'title' => t('Edit Redhen Contact revisions'),
    ),
    'delete redhen contact revisions' => array(
      'title' => t('Delete Redhen Contact revisions'),
    ),
  );
}

/**
 * Display a contact.
 *
 * @param RedhenContact $contact
 *   A Fully loaded contact object.
 *
 * @return array
 *   Render array.
 */
function redhen_contact_view(RedhenContact $contact, $view_mode = 'full', $langcode = NULL, $page = NULL) {
  return $contact
    ->view($view_mode, $langcode, $page);
}

/**
 * Title callback for hook_menu().
 *
 * @param RedhenContact $contact
 *   A loaded contact object.
 *
 * @return string
 *   Contact label.
 */
function redhen_contact_contact_title(RedhenContact $contact) {
  return $contact
    ->label();
}

/**
 * Implements hook_user_delete().
 */
function redhen_contact_user_delete($account) {

  // Delete any associated contacts.
  if ($contact = redhen_contact_load_by_user($account)) {
    $return = $contact
      ->delete();
  }
}

/**
 * Implements hook_user_cancel().
 */
function redhen_contact_user_cancel($edit, $account, $method) {
  switch ($method) {
    case 'user_cancel_block_unpublish':

      // Archive the contact, but keep the association.
      if ($contact = redhen_contact_load_by_user($account)) {
        $contact
          ->setState(REDHEN_STATE_ARCHIVED);
        $contact
          ->save();
      }
      break;
    case 'user_cancel_reassign':

      // Unlink the entities, but do not archive the contact.
      if ($contact = redhen_contact_load_by_user($account)) {
        $contact
          ->deleteUser(TRUE);
        $contact
          ->save();
      }
      break;
  }
}

/**
 * Implements hook_field_extra_fields().
 */
function redhen_contact_field_extra_fields() {
  $extra = array();
  foreach (redhen_contact_get_types() as $type => $contact_type) {
    $extra['redhen_contact'][$type] = array(
      'form' => array(
        'name' => array(
          'label' => t('Contact name'),
          'description' => t('Contact name'),
          'weight' => 0,
        ),
      ),
      'display' => array(
        'name' => array(
          'label' => t('Name'),
          'description' => t('Contact name.'),
          'weight' => 0,
        ),
        'redhen_state' => array(
          'label' => t('State'),
          'description' => t('Contact state'),
          'weight' => 0,
        ),
        'user' => array(
          'label' => t('User'),
          'description' => t('Drupal user'),
          'weight' => 0,
        ),
      ),
    );
  }
  return $extra;
}

/**
 * Gets an array of all contact types, keyed by the name.
 *
 * @param string $name
 *   If set, the type with the given name is returned.
 */
function redhen_contact_get_types($name = NULL) {
  $types = entity_load_multiple_by_name('redhen_contact_type', isset($name) ? array(
    $name,
  ) : FALSE);
  return isset($name) ? reset($types) : $types;
}

/**
 * Return an associative array of contact types to be used as an options list.
 *
 * @return array
 *   Keyed by name with a label value.
 */
function redhen_contact_type_options_list() {
  $options = array();
  foreach (redhen_contact_get_types() as $type) {
    $options[$type->name] = $type
      ->label();
  }
  return $options;
}

/**
 * Access callback for the entity API.
 */
function redhen_contact_type_access($op, $type = NULL, $account = NULL) {
  return user_access('administer redhen_contact types', $account);
}

/**
 * Menu argument loader; Load a contact type by string.
 *
 * @param string $type
 *   The machine-readable name of a contact type to load.
 *
 * @return array.
 *   A contact type array or FALSE if $type does not exist.
 */
function redhen_contact_type_load($type) {
  return redhen_contact_get_types($type);
}

/**
 * Saves a model type to the db.
 */
function redhen_contact_type_save(RedhenContactType $type) {
  $type
    ->save();
}

/**
 * Deletes a model type from the db.
 */
function redhen_contact_type_delete(RedhenContactType $type) {
  $type
    ->delete();
}

/**
 * Returns HTML for a list of available node types for node creation.
 *
 * @param array $variables
 *   An associative array containing:
 *   - content: An array of content types.
 *
 * @ingroup themeable
 */
function theme_redhen_contact_add_list($variables) {
  $content = $variables['content'];
  $output = '';
  if ($content) {
    $output = '<dl class="node-type-list">';
    foreach ($content as $item) {
      $output .= '<dt>' . l($item['title'], $item['href'], $item['localized_options']) . '</dt>';
      $output .= '<dd>' . filter_xss_admin($item['description']) . '</dd>';
    }
    $output .= '</dl>';
  }
  else {
    $output = '<p>' . t('You have not created any contact types yet. Go to the <a href="@create-contact">contact type creation page</a> to add a new contact type.', array(
      '@create-contact' => url('admin/structure/redhen/contact_types'),
    )) . '</p>';
  }
  return $output;
}

/**
 * Theme function for contact list.
 */
function theme_redhen_contact_list($variables) {
  $header = $variables['header'];
  $rows = $variables['rows'];
  $render['table'] = array(
    '#theme' => 'table',
    '#header' => $header,
    '#rows' => $rows,
    '#empty' => t('No contacts available.'),
  );
  $render['pager'] = array(
    '#theme' => 'pager',
  );
  return render($render);
}

/**
 * Implements hook_redhen_settings().
 */
function redhen_contact_redhen_settings() {
  $contact_type_options = redhen_contact_type_options_list();
  return array(
    'redhen_contact_email' => array(
      '#type' => 'fieldset',
      '#title' => t('Email settings'),
      '#weight' => 0,
      'settings' => array(
        REDHEN_CONTACT_REQUIRE_EMAIL => array(
          '#type' => 'checkbox',
          '#title' => t('Require contacts to have a valid email address'),
          '#description' => t('Controls the contact form validation. Must be true to enable Drupal user connections keyed on email and contact email mirroring.'),
          '#default_value' => variable_get(REDHEN_CONTACT_REQUIRE_EMAIL, TRUE),
        ),
        REDHEN_CONTACT_CONNECT_USERS => array(
          '#type' => 'checkbox',
          '#title' => t('Connect users to Redhen contacts'),
          '#description' => t('If checked, Redhen will attempt to connect Drupal users to Redhen contacts by matching email addresses when a contact is updated.'),
          '#default_value' => variable_get(REDHEN_CONTACT_CONNECT_USERS, FALSE),
          '#states' => array(
            'enabled' => array(
              ':input[name="' . REDHEN_CONTACT_REQUIRE_EMAIL . '"]' => array(
                'checked' => TRUE,
              ),
            ),
          ),
        ),
        REDHEN_CONTACT_MIRROR_EMAIL => array(
          '#type' => 'checkbox',
          '#title' => t('Mirror RedHen Contact email to Drupal user'),
          '#description' => t('If checked, RedHen will mirror the primary email of a RedHen Contact with the email of the linked user account. The email field on the Drupal user form will also be disabled.'),
          '#default_value' => variable_get(REDHEN_CONTACT_MIRROR_EMAIL, FALSE),
          '#states' => array(
            'enabled' => array(
              ':input[name="' . REDHEN_CONTACT_CONNECT_USERS . '"]' => array(
                'checked' => TRUE,
              ),
            ),
          ),
        ),
        REDHEN_CONTACT_EMBED_ON_USER_FORM => array(
          '#type' => 'checkbox',
          '#title' => t('Embed Redhen Contact Fields on the User edit form'),
          '#description' => t('If checked, the RedHen Contact tab on users will be removed, and the Contact edit fields will instead be attached to the bottom of the User Edit form.'),
          '#default_value' => variable_get(REDHEN_CONTACT_EMBED_ON_USER_FORM, FALSE),
          '#states' => array(
            'enabled' => array(
              ':input[name="' . REDHEN_CONTACT_CONNECT_USERS . '"]' => array(
                'checked' => TRUE,
              ),
            ),
          ),
        ),
        REDHEN_CONTACT_DELETE_USER_WITH_CONTACT => array(
          '#type' => 'checkbox',
          '#title' => t('Delete Users when their connected Redhen Contacts are deleted (WARNING: automated User deletion!)'),
          '#description' => t('If checked, deleted Redhen Contacts will be checked for connected users, and those users will be automatically deleted as well.'),
          '#default_value' => variable_get(REDHEN_CONTACT_DELETE_USER_WITH_CONTACT, FALSE),
          '#states' => array(
            'enabled' => array(
              ':input[name="' . REDHEN_CONTACT_CONNECT_USERS . '"]' => array(
                'checked' => TRUE,
              ),
            ),
          ),
        ),
        REDHEN_CONTACT_USER_EMAIL_TYPE => array(
          '#type' => 'checkboxes',
          '#multiple' => TRUE,
          '#options' => $contact_type_options,
          '#title' => t('User email contact types'),
          '#description' => t('Restrict which contact types will connect to Drupal user accounts by email address. Leave blank to allow ANY contact type (default).'),
          '#default_value' => variable_get(REDHEN_CONTACT_USER_EMAIL_TYPE, array()),
          '#states' => array(
            'enabled' => array(
              ':input[name="' . REDHEN_CONTACT_CONNECT_USERS . '"]' => array(
                'checked' => TRUE,
              ),
            ),
          ),
          '#access' => count($contact_type_options) > 1,
        ),
      ),
    ),
    REDHEN_CONTACT_ALTER_USERNAME => array(
      '#type' => 'checkbox',
      '#title' => t('Display username as contact label'),
      '#description' => t("If checked, RedHen will alter the display of the Drupal username to match a linked contact's label."),
      '#default_value' => variable_get(REDHEN_CONTACT_ALTER_USERNAME, FALSE),
    ),
    REDHEN_CONTACT_ALTER_COMMENT_AUTHOR => array(
      '#type' => 'checkbox',
      '#title' => t('Use contact as comment author'),
      '#description' => t("If checked, RedHen will alter the display of Comments to display related contact names and link to redhen contacts for users with related RedHen Contacts."),
      '#default_value' => variable_get(REDHEN_CONTACT_ALTER_COMMENT_AUTHOR, FALSE),
    ),
    'redhen_user_registration_form' => array(
      '#type' => 'fieldset',
      '#title' => t('User registration'),
      'settings' => array(
        REDHEN_CONTACT_REG => array(
          '#type' => 'checkbox',
          '#options' => array(
            1,
            1,
          ),
          '#title' => t('Create a contact during user registration'),
          '#default_value' => variable_get(REDHEN_CONTACT_REG, FALSE),
        ),
        REDHEN_CONTACT_REG_TYPE => array(
          '#type' => 'select',
          '#options' => $contact_type_options,
          '#title' => t('Default contact type'),
          '#description' => t('Select the default contact type to create during registration. This can be overriden by appending the contact type machine name in the registration url.'),
          '#default_value' => variable_get(REDHEN_CONTACT_REG_TYPE, FALSE),
          '#states' => array(
            'invisible' => array(
              ':input[name="redhen_contact_reg"]' => array(
                'checked' => FALSE,
              ),
            ),
          ),
        ),
        REDHEN_CONTACT_REG_UPDATE => array(
          '#type' => 'checkbox',
          '#options' => array(
            1,
            1,
          ),
          '#title' => t('Update and link existing contacts'),
          '#description' => t('If a contact is found with the same email as the new Drupal user, it will be updated and linked to the new account.'),
          '#default_value' => variable_get(REDHEN_CONTACT_REG_UPDATE, FALSE),
        ),
        REDHEN_CONTACT_REG_UPDATE_FIELDS => array(
          '#type' => 'checkbox',
          '#options' => array(
            1,
            1,
          ),
          '#title' => t('Update contact fields'),
          '#description' => t('Should the contact fields be updated?'),
          '#default_value' => variable_get(REDHEN_CONTACT_REG_UPDATE_FIELDS, FALSE),
          '#states' => array(
            'invisible' => array(
              ':input[name="redhen_contact_reg_update"]' => array(
                'checked' => FALSE,
              ),
            ),
          ),
        ),
      ),
    ),
    REDHEN_CONTACT_REQUIRE_FIRST_NAME => array(
      '#type' => 'checkbox',
      '#options' => array(
        1,
        1,
      ),
      '#title' => t('Require contacts to have non-empty first name'),
      '#description' => t('Uncheck this if contact first name field should be optional.'),
      '#default_value' => variable_get(REDHEN_CONTACT_REQUIRE_FIRST_NAME, TRUE),
    ),
  );
}

/**
 * Utility function for checking settings related to contact->user connections.
 *
 * @param string $setting
 *   Setting string - should be a REDHEN_CONTACT_* setting constant.
 * @param object $contact
 *   Contact object.
 *
 * @return bool
 *   True if setting is enabled for connecting the contact to user, else false.
 */
function redhen_contact_user_email_setting($setting, $contact) {
  $user_email_type = variable_get(REDHEN_CONTACT_USER_EMAIL_TYPE, array());
  if ($user_email_type && isset($contact->type) && !in_array($contact->type, $user_email_type)) {
    return FALSE;
  }
  switch ($setting) {
    case REDHEN_CONTACT_REQUIRE_EMAIL:
      return variable_get($setting, TRUE);
  }
  return variable_get($setting, FALSE);
}

/**
 * Return a RedHen contact associated with a given Drupal account.
 *
 * @param object $account
 *   User object.
 *
 * @return mixed
 *   RedhenContact or FALSE.
 */
function redhen_contact_user_contact($account) {
  $contact = FALSE;
  $result = db_select('redhen_contact_user', 'rcu')
    ->fields('rcu', array(
    'contact_id',
  ))
    ->condition('uid', $account->uid)
    ->condition('status', 1)
    ->execute()
    ->fetchCol();
  if ($result) {
    $contact = redhen_contact_load(reset($result));
  }
  return $contact;
}

/**
 * Implements hook_entity_delete().
 *
 * Allow users to be deleted automatically when their associated contacts are
 * deleted, based on a setting.
 */
function redhen_contact_entity_delete($entity, $type) {
  if (variable_get(REDHEN_CONTACT_DELETE_USER_WITH_CONTACT, FALSE)) {
    if ($type == 'redhen_contact' && !empty($entity->uid)) {

      // Delete associated user when the contact is deleted.
      user_delete($entity->uid);
    }
  }
}

/**
 * Implements hook_query_TAG_alter().
 *
 * Check if label is one of the conditions and alter to search on first and last
 * name if it is.
 */
function redhen_contact_query_redhen_contact_label_alter(QueryAlterableInterface $query) {

  // Can't access the properties of $query directly.
  $where =& $query
    ->conditions();
  foreach ($where as $id => $condition) {

    // If we're trying to search for redhen_contact.label, alter the query to
    // search in both first and last name fields.
    if (isset($condition['field']) && is_string($condition['field']) && $condition['field'] == 'redhen_contact.label') {
      unset($where[$id]);
      $or = db_or()
        ->condition('redhen_contact.first_name', $condition['value'], $condition['operator'])
        ->condition('redhen_contact.last_name', $condition['value'], $condition['operator']);
      $query
        ->condition($or);
    }
  }
}

/**
 * Load a contact record from a user account.
 *
 * @param object $account
 *   User object.
 * @param int $state
 *   Redhen state. Defaults to active.
 *
 * @return mixed
 *   Contact or FALSE if not found.
 */
function redhen_contact_load_by_user($account, $state = REDHEN_STATE_ACTIVE) {
  $contact =& drupal_static(__FUNCTION__ . $account->uid, FALSE);
  if (!$contact && !empty($account->uid)) {
    $contacts = redhen_contact_load_multiple(FALSE, array(
      'uid' => $account->uid,
      'redhen_state' => $state,
    ));
    if (!empty($contacts)) {

      // There should always be only a single active user linked to an account.
      $contact = reset($contacts);
    }
  }
  return $contact;
}

/**
 * Load all contact entities for an email address.
 *
 * @param string $mail
 *   Required: an email address.
 * @param string $state
 *   RedHen state. Defaults to active.
 *
 * @return array|bool
 *   An array of RedHen Contact entities or FALSE if no match found.
 */
function redhen_contact_load_by_mail($mail, $state = REDHEN_STATE_ACTIVE) {
  $contacts =& drupal_static(__FUNCTION__ . $mail, FALSE);
  if (!$contacts) {
    $query = new EntityFieldQuery();
    $query
      ->entityCondition('entity_type', 'redhen_contact')
      ->fieldCondition('redhen_contact_email', 'value', $mail, '=');
    if (!is_null($state)) {
      $query
        ->propertyCondition('redhen_state', $state);
    }
    $result = $query
      ->execute();
    if (!empty($result)) {
      $contacts = redhen_contact_load_multiple(array_keys($result['redhen_contact']));
    }
  }
  return $contacts;
}

/**
 * Implements hook_username_alter().
 */
function redhen_contact_username_alter(&$name, $account) {
  if ($account && variable_get(REDHEN_CONTACT_ALTER_USERNAME, FALSE)) {
    $contact = redhen_contact_load_by_user($account);

    // Display the contact label if the user is linked to a contact.
    if ($contact) {
      $name = $contact
        ->label();
    }
  }
}

/**
 * Create a new contact object.
 *
 * @param array $values
 *   Associative array of values. At least include array('type' => $type).
 *
 * @return RedhenContact
 *   New contact entity.
 */
function redhen_contact_create(array $values = array()) {
  return entity_get_controller('redhen_contact')
    ->create($values);
}

/**
 * Access callback for redhen_contact_user_categories().
 */
function redhen_contact_user_contact_access($account = NULL) {
  global $user;
  if (!$account) {
    $account = $user;
  }
  $contact = redhen_contact_load_by_user($account);

  // There is no contact linked to this user account.
  if (!$contact) {
    return FALSE;
  }

  // User is editing their own contact information.
  if ($contact->uid == $user->uid && user_access('edit own redhen contact')) {
    return TRUE;
  }

  // Privileged user trying to edit contact information.
  if (redhen_contact_access('edit', $contact, $user)) {
    return TRUE;
  }
  return FALSE;
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function redhen_contact_form_user_profile_form_alter(&$form, &$form_state) {

  // If we're mirroring the contact's email address - disable the field.
  $contact = redhen_contact_load_by_user($form['#user']);
  if ($contact) {
    if ($form['#user_category'] == 'account' && redhen_contact_user_email_setting(REDHEN_CONTACT_MIRROR_EMAIL, $contact)) {
      $form['account']['mail']['#disabled'] = TRUE;
      $form['account']['mail']['#description'] .= ' ' . t('The email address for this account is managed by RedHen.');
    }
    if ($form['#user_category'] == 'account' && redhen_contact_user_email_setting(REDHEN_CONTACT_EMBED_ON_USER_FORM, $contact) && redhen_contact_user_contact_access()) {
      if ($form['account']['mail']['#disabled']) {

        // Just hide the email field since it will display on the contact form:
        $form['account']['mail']['#access'] = FALSE;
      }
      _redhen_contact_user_embed_contact_form($form, $form_state, $contact);

      // Add a submit handler for handling the contact form data.
      $form['#submit'][] = 'redhen_contact_user_update_submit';
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function redhen_contact_form_user_register_form_alter(&$form, &$form_state) {

  // Check if enabled.
  if (variable_get(REDHEN_CONTACT_REG, FALSE)) {

    // Get menu item to check for the overriden contact type parameter, but only
    // when a user is registering from user/register.
    $menu_item = menu_get_item();
    if ($menu_item['original_map'][0] == 'user' && $menu_item['original_map'][1] == 'register' && isset($menu_item['original_map'][2])) {
      $contact_type = $menu_item['original_map'][2];
    }
    else {

      // If not parameter, use the default Contact type.
      $contact_type = variable_get(REDHEN_CONTACT_REG_TYPE, FALSE);
    }

    // If a valid contact type was found.
    if (array_key_exists($contact_type, redhen_contact_get_types())) {
      $contact_object = redhen_contact_create(array(
        'type' => $contact_type,
      ));
      _redhen_contact_user_embed_contact_form($form, $form_state, $contact_object);

      // Add a submit handler for handling the contact form data.
      $form['#submit'][] = 'redhen_contact_user_registration_submit';

      // Hide the Contact email field, we will use the user mail field.
      $form['redhen_contact']['form']['redhen_contact_email']['#access'] = FALSE;
      $form['#validate'][] = 'redhen_contact_user_registration_validate';
    }
    else {
      drupal_set_message(t('Invalid RedHen contact type parameter.'));
    }
  }
}

/**
 * Helper function to embed a contact form on a user form.
 *
 * Usage note: make sure to add a submit handler, otherwise this form data will
 * just be ignored.
 *
 * @param array $form
 *   Form array.
 * @param array $form_state
 *   Form state array.
 * @param RedhenContact $contact
 *   The contact to build the form on.
 */
function _redhen_contact_user_embed_contact_form(&$form, &$form_state, RedhenContact $contact) {
  module_load_include('inc', 'redhen_contact', 'includes/redhen_contact.forms');

  // Get contact type form.
  $form['redhen_contact'] = array(
    '#type' => 'fieldset',
    '#title' => t('Contact information'),
    'form' => redhen_contact_contact_form(array(), $form_state, $contact),
  );

  // Unset the contact forms action, we will use the parent form's actions.
  unset($form['redhen_contact']['form']['actions']);
}

/**
 * Registration form RedHen contact validation handler.
 */
function redhen_contact_user_registration_validate($form, &$form_state) {
  $contact_type = $form_state['redhen_contact']
    ->bundle();
  if (empty($form_state['values']['mail'])) {

    // User registration form is invalid anyway, let that validator handle it.
    return;
  }
  $existing_contact = redhen_contact_load_by_mail($form_state['values']['mail']);
  $contact = $existing_contact ? current($existing_contact) : array();
  $update_existing = variable_get(REDHEN_CONTACT_REG_UPDATE, FALSE);

  // We have an existing contact, but it's of a different type.
  if ($existing_contact && $contact
    ->bundle() !== $contact_type) {
    form_set_error('', t('A Contact of type %type is already associated with the email address %email.', array(
      '%type' => $contact
        ->bundle(),
      '%email' => $form_state['values']['mail'],
    )));
  }

  // We don't want to update contacts, but found an existing match.
  if ($existing_contact && !$update_existing) {
    form_set_error('', t('A contact already exists with that email address.'));
  }

  // Existing contact is already linked to a user.
  if ($existing_contact && !is_null($contact->uid) && $update_existing) {
    form_set_error('mail', t('A contact with that email address is already linked to a Drupal user.'));
  }
}

/**
 * Update form RedHen contact submit handler.
 *
 * Updates a related Contact on user update.
 *
 * @param array $form
 *   Form array.
 * @param array $form_state
 *   Form state array.
 */
function redhen_contact_user_update_submit($form, &$form_state) {
  $contact = $form_state['redhen_contact'];
  $message = _redhen_contact_user_submission_apply($form, $form_state, $contact);
  redhen_contact_save($contact);

  // Only display this message to CRM users to avoid confusion.
  if (user_access('access redhen contacts')) {
    drupal_set_message($message);
  }
}

/**
 * Registration form RedHen contact submit handler.
 *
 * Creates a Contact on user registration.
 *
 * @param array $form
 *   Form array.
 * @param array $form_state
 *   Form state array.
 */
function redhen_contact_user_registration_submit($form, &$form_state) {
  $contact = $form_state['redhen_contact'];
  $uid = $form_state['user']->uid;

  // Does a contact already exist with that email address?
  $existing_contact = redhen_contact_load_by_mail($form_state['values']['mail']);
  $contact = $existing_contact ? current($existing_contact) : $contact;

  // Set user.
  $contact->uid = $uid;

  // If set to update fields, do so.
  if (variable_get(REDHEN_CONTACT_REG_UPDATE_FIELDS, FALSE) == TRUE || !empty($contact->is_new)) {
    $contact->author_uid = $uid;
    $message_update = _redhen_contact_user_submission_apply($form, $form_state, $contact, TRUE);

    // Set email address.
    redhen_contact_property_email_set($contact, NULL, $form_state['values']['mail']);
  }
  redhen_contact_save($contact);
  $message = t('User has been linked to the contact %name.', array(
    '%name' => $contact
      ->label(),
  ));
  if (isset($message_update)) {
    $message .= ' ' . $message_update;
  }

  // Update form_state contact for later processing.
  $form_state['redhen_contact'] = $contact;

  // Only display this message to CRM users to avoid confusion.
  if (user_access('access redhen contacts')) {
    drupal_set_message($message);
  }
}

/**
 * Helper function for handling Contact Form values submitted via User forms.
 *
 * This happens when a RedHen Contact form is embedded in a User form via a form
 * alter hook, then the from is submitted. Note that this function updates the
 * $contact, but does not save the changes.
 *
 * @param array $form
 *   Form array.
 * @param array $form_state
 *   Form state array.
 * @param RedhenContact $contact
 *   RedhenContact to update.
 * @param bool $limit_values
 *   Whether to limit updated values to non-null fields.
 *
 * @return string
 *   Status message.
 */
function _redhen_contact_user_submission_apply($form, $form_state, RedhenContact $contact, $limit_values = FALSE) {
  if ($limit_values) {
    $value_state = redhen_contact_user_registration_form_state($form['redhen_contact']['form'], $form_state);
  }
  else {
    $value_state = $form_state;
  }

  // Save default parameters back into the $contact object.
  $contact->first_name = $form_state['values']['first_name'];
  $contact->middle_name = $form_state['values']['middle_name'];
  $contact->last_name = $form_state['values']['last_name'];

  // Notify field widgets using the limited state variable.
  field_attach_submit('redhen_contact', $contact, $form['redhen_contact']['form'], $value_state);
  return t('The contact was updated with the information provided.');
}

/**
 * Submit handler for the redhen contact user category.
 */
function redhen_contact_user_form_submit($form, &$form_state) {
  $uri = user_uri($form['#user']);
  $form_state['redirect'] = $uri;
}

/**
 * Implements hook_user_view().
 */
function redhen_contact_user_view($account, $view_mode, $langcode) {

  // Include contact view if access allowed.
  if ($contact = redhen_contact_load_by_user($account)) {

    // A Contact exists for this account. Does the current user have access?
    if (redhen_contact_access('view', $contact)) {
      $view_mode = variable_get('redhen_contact_view_mode', $view_mode);
      $account->content['redhen_contact'] = redhen_contact_view($contact, $view_mode);
    }
  }
}

/**
 * Callback to get $contact->full_name.
 */
function redhen_contact_property_full_name_get(RedhenContact $contact, array $options, $property_name, $entity_type) {
  $name = $contact->first_name . (empty($contact->middle_name) ? '' : ' ') . $contact->middle_name . (empty($contact->first_name) ? '' : ' ') . $contact->last_name;
  drupal_alter('redhen_contact_name', $name, $contact);
  return $name;
}

/**
 * Callback to get $contact->user.
 */
function redhen_contact_property_user_get(RedhenContact $contact, array $options, $property_name, $entity_type) {
  if (is_numeric($contact->uid)) {
    return user_load($contact->uid);
  }
}

/**
 * Callback to set $contact->user.
 */

/**
 * Callback to set $contact->user.
 *
 * @param RedhenContact $contact
 *   Contact entity.
 * @param string $name
 *   Property name.
 * @param int $value
 *   Property value. User uid in this case.
 */
function redhen_contact_property_user_set(RedhenContact $contact, $name, $value, $langcode, $type, $info) {
  $contact->uid = $value;
}

/**
 * Entity metadata property getter for default email.
 *
 * @return string
 *   Default email address.
 */
function redhen_contact_property_email_get(RedhenContact $contact, array $options, $property_name, $entity_type) {
  if (!empty($contact->{REDHEN_CONTACT_EMAIL_FIELD})) {
    foreach ($contact->{REDHEN_CONTACT_EMAIL_FIELD}[LANGUAGE_NONE] as $email) {
      if ($email['default']) {
        return $email['value'];
      }
    }
  }
  return '';
}

/**
 * Entity metadata property setter for default email.
 */
function redhen_contact_property_email_set(RedhenContact $contact, $name, $value) {
  $key = 0;

  // Reset the default flag for any existing emails.
  if (!empty($contact->{REDHEN_CONTACT_EMAIL_FIELD})) {
    foreach ($contact->{REDHEN_CONTACT_EMAIL_FIELD}[LANGUAGE_NONE] as $key => $email) {
      $contact->{REDHEN_CONTACT_EMAIL_FIELD}[LANGUAGE_NONE][$key]['default'] = 0;
    }
  }

  // Now set the new email as default.
  $contact->{REDHEN_CONTACT_EMAIL_FIELD}[LANGUAGE_NONE][$key] = array(
    'value' => $value,
    'default' => 1,
  );
}

/**
 * Return form_state that includes the values from the visible form elements.
 *
 * @param array $form
 *   The RedHen contact form.
 * @param array $form_state
 *   The RedHen contact form state.
 *
 * @return array
 *   The modified form_state array.
 */
function redhen_contact_user_registration_form_state($form, $form_state) {
  $limited_state = $form_state;
  $limited_state['values'] = array();
  foreach (element_children($form) as $key) {
    $child = $form[$key];

    // Skip un-accessible children.
    if (isset($child['#access']) && !$child['#access']) {
      continue;
    }
    if (isset($form_state['values'][$key])) {
      $limited_state['values'][$key] = $form_state['values'][$key];
    }
  }
  return $limited_state;
}

/**
 * Implements hook_rules_file_info().
 */
function redhen_contact_rules_file_info() {
  return array(
    'includes/redhen_contact.rules',
  );
}

/**
 * Implements theme_preprocess_comment().
 *
 * Use the RedHen Contact as the comment author.
 */
function redhen_contact_preprocess_comment(&$variables) {
  if (variable_get(REDHEN_CONTACT_ALTER_COMMENT_AUTHOR, FALSE) && ($contact = redhen_contact_load_by_user(user_load($variables['comment']->uid)))) {
    if (entity_access('view', 'redhen_contact', $contact)) {
      $contact_uri = $contact
        ->uri();
      $variables['author'] = l($contact
        ->label(), $contact_uri['path'], array(
        'attributes' => array(
          'title' => 'View profile',
          'class' => 'username',
        ),
      ));
    }
    else {
      $variables['author'] = $contact
        ->label();
    }
  }
}

/**
 * Implements hook_query_TAG_alter().
 *
 * For tag redhen_contact_generic_selection.
 */
function redhen_contact_query_redhen_contact_generic_selection_alter(QueryAlterableInterface $query) {

  // Add an OR condition for first_name and last_name properties.
  $search_string = $query->alterMetaData['search_string'];
  $tables = $query
    ->getTables();
  $table = $tables['redhen_contact']['alias'];
  $or = db_or()
    ->condition("{$table}.first_name", "%{$search_string}%", 'LIKE')
    ->condition("{$table}.last_name", "%{$search_string}%", 'LIKE');
  $query
    ->condition($or);
}

/**
 * Implements hook_redhen_relation_role_permissions().
 */
function redhen_contact_redhen_relation_role_permissions() {
  $roles = array(
    'edit_contact' => array(
      'label' => 'Edit Contact',
    ),
    'delete_contact' => array(
      'label' => 'Delete Contact',
    ),
  );
  return $roles;
}

Functions

Namesort descending Description
redhen_contact_access Checks contact access for various operations.
redhen_contact_contact_title Title callback for hook_menu().
redhen_contact_create Create a new contact object.
redhen_contact_delete_multiple Deletes multiple contacts by ID.
redhen_contact_entity_delete Implements hook_entity_delete().
redhen_contact_entity_info Implements hook_entity_info().
redhen_contact_entity_info_alter Implements hook_entity_info_alter().
redhen_contact_entity_property_info_alter Implements hook_entity_property_info_alter().
redhen_contact_field_extra_fields Implements hook_field_extra_fields().
redhen_contact_form_user_profile_form_alter Implements hook_form_FORM_ID_alter().
redhen_contact_form_user_register_form_alter Implements hook_form_FORM_ID_alter().
redhen_contact_get_types Gets an array of all contact types, keyed by the name.
redhen_contact_load Loads a contact by ID.
redhen_contact_load_by_mail Load all contact entities for an email address.
redhen_contact_load_by_user Load a contact record from a user account.
redhen_contact_load_by_user_callback Wrapper around redhen_contact_load_by_user to use as user property callback.
redhen_contact_load_multiple Loads multiple contacts by ID or based on a set of matching conditions.
redhen_contact_menu Implements hook_menu().
redhen_contact_menu_local_tasks_alter Implements hook_menu_local_tasks_alter().
redhen_contact_permission Implements hook_permission().
redhen_contact_preprocess_comment Implements theme_preprocess_comment().
redhen_contact_property_email_get Entity metadata property getter for default email.
redhen_contact_property_email_set Entity metadata property setter for default email.
redhen_contact_property_full_name_get Callback to get $contact->full_name.
redhen_contact_property_user_get Callback to get $contact->user.
redhen_contact_property_user_set Callback to set $contact->user.
redhen_contact_query_redhen_contact_generic_selection_alter Implements hook_query_TAG_alter().
redhen_contact_query_redhen_contact_label_alter Implements hook_query_TAG_alter().
redhen_contact_redhen_relation_role_permissions Implements hook_redhen_relation_role_permissions().
redhen_contact_redhen_settings Implements hook_redhen_settings().
redhen_contact_revision_load Loads a contact revision by ID.
redhen_contact_rules_file_info Implements hook_rules_file_info().
redhen_contact_save Saves a contact.
redhen_contact_theme Implements hook_theme().
redhen_contact_type_access Access callback for the entity API.
redhen_contact_type_delete Deletes a model type from the db.
redhen_contact_type_load Menu argument loader; Load a contact type by string.
redhen_contact_type_options_list Return an associative array of contact types to be used as an options list.
redhen_contact_type_save Saves a model type to the db.
redhen_contact_username_alter Implements hook_username_alter().
redhen_contact_user_cancel Implements hook_user_cancel().
redhen_contact_user_contact Return a RedHen contact associated with a given Drupal account.
redhen_contact_user_contact_access Access callback for redhen_contact_user_categories().
redhen_contact_user_delete Implements hook_user_delete().
redhen_contact_user_email_setting Utility function for checking settings related to contact->user connections.
redhen_contact_user_form_submit Submit handler for the redhen contact user category.
redhen_contact_user_registration_form_state Return form_state that includes the values from the visible form elements.
redhen_contact_user_registration_submit Registration form RedHen contact submit handler.
redhen_contact_user_registration_validate Registration form RedHen contact validation handler.
redhen_contact_user_update_submit Update form RedHen contact submit handler.
redhen_contact_user_view Implements hook_user_view().
redhen_contact_view Display a contact.
theme_redhen_contact_add_list Returns HTML for a list of available node types for node creation.
theme_redhen_contact_list Theme function for contact list.
_redhen_contact_user_embed_contact_form Helper function to embed a contact form on a user form.
_redhen_contact_user_submission_apply Helper function for handling Contact Form values submitted via User forms.

Constants