You are here

salesforce_mapping.module in Salesforce Suite 7.3

File

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

/**
 * @file
 * Manages Salesforce object and Drupal entity mappings.
 */
module_load_include('inc', 'salesforce_mapping', 'includes/salesforce_mapping.fieldmap_type');

/**
 * Bit flags defining when a data sync should take place for a given mapping.
 */
define('SALESFORCE_MAPPING_SYNC_OFF', 0x0);
define('SALESFORCE_MAPPING_SYNC_DRUPAL_CREATE', 0x1);
define('SALESFORCE_MAPPING_SYNC_DRUPAL_UPDATE', 0x2);
define('SALESFORCE_MAPPING_SYNC_DRUPAL_DELETE', 0x4);
define('SALESFORCE_MAPPING_SYNC_SF_CREATE', 0x8);
define('SALESFORCE_MAPPING_SYNC_SF_UPDATE', 0x10);
define('SALESFORCE_MAPPING_SYNC_SF_DELETE', 0x20);

/**
 * Field mapping direction constants.
 */
define('SALESFORCE_MAPPING_DIRECTION_DRUPAL_SF', 'drupal_sf');
define('SALESFORCE_MAPPING_DIRECTION_SF_DRUPAL', 'sf_drupal');
define('SALESFORCE_MAPPING_DIRECTION_SYNC', 'sync');

/**
 * Field mapping Master or no record type (default) constant.
 */
define('SALESFORCE_MAPPING_DEFAULT_RECORD_TYPE', 'default');

/**
 * Delimiter used in Salesforce multipicklists.
 */
define('SALESFORCE_MAPPING_ARRAY_DELIMITER', ';');

/**
 * Field mapping maximum name length.
 */
define('SALESFORCE_MAPPING_NAME_LENGTH', 128);

/**
 * Mapping object sync statuses.
 */
define('SALESFORCE_MAPPING_STATUS_SUCCESS', 1);
define('SALESFORCE_MAPPING_STATUS_ERROR', 0);

/**
 * Access callback for managing Salesforce mappings.
 */
function salesforce_mappings_access() {
  if (!module_exists('salesforce_pull') && !module_exists('salesforce_push')) {
    return FALSE;
  }
  if (user_access('administer salesforce mapping')) {
    $sfapi = salesforce_get_api();
    return $sfapi
      ->isAuthorized();
  }
  return FALSE;
}

/**
 * Implements hook_page_alter().
 */
function salesforce_mapping_page_alter(&$page) {
  if (current_path() == 'admin/structure/salesforce' && !module_exists('salesforce_pull') && !module_exists('salesforce_push')) {
    drupal_set_message(t('At least one sync method (Push or Pull) must be <a href="/admin/modules">enabled</a> to configure Salesforce Mappings.'), 'error', FALSE);
  }
}

/**
 * Implements hook_entity_info().
 */
function salesforce_mapping_entity_info() {
  $return = array(
    'salesforce_mapping' => array(
      'label' => t('Salesforce Mapping'),
      'controller class' => 'EntityAPIControllerExportable',
      'entity class' => 'SalesforceMapping',
      'base table' => 'salesforce_mapping',
      'uri callback' => 'entity_class_uri',
      'fieldable' => FALSE,
      'exportable' => TRUE,
      'module' => 'salesforce_mapping',
      'entity keys' => array(
        'id' => 'salesforce_mapping_id',
        'name' => 'name',
        'label' => 'label',
      ),
      'bundle keys' => array(
        'bundle' => 'type',
      ),
      'bundles' => array(
        'salesforce_mapping' => array(
          'label' => 'Salesforce Mapping',
        ),
      ),
      // Enable the entity API's admin UI.
      'admin ui' => array(
        'path' => 'admin/structure/salesforce/mappings',
        'file' => 'salesforce_mapping.admin.inc',
        'file path' => drupal_get_path('module', 'salesforce_mapping') . '/includes',
        'controller class' => 'SalesforceMappingUIController',
      ),
      'access callback' => 'salesforce_mappings_access',
    ),
    'salesforce_mapping_object' => array(
      'label' => t('Salesforce Object Mapping'),
      'controller class' => 'SalesforceMappingObjectController',
      'entity class' => 'SalesforceMappingObject',
      'metadata controller class' => 'SalesforceMappingObjectMetadataController',
      'base table' => 'salesforce_mapping_object',
      'revision table' => 'salesforce_mapping_object_revision',
      'label callback' => 'entity_class_label',
      'uri callback' => 'entity_class_uri',
      'fieldable' => FALSE,
      'exportable' => FALSE,
      'module' => 'salesforce_mapping',
      'entity keys' => array(
        'id' => 'salesforce_mapping_object_id',
        'label' => 'salesforce_mapping_object_id',
        'revision' => 'revision_id',
      ),
      'access callback' => 'salesforce_mapping_object_access',
      // Prevent Redirect alteration of the mapping object form.
      'redirect' => FALSE,
    ),
  );
  return $return;
}

/**
 * Implements hook_entity_property_info().
 */
function salesforce_mapping_entity_property_info() {
  $info = array();
  $entities = salesforce_mapping_get_mapped_entities();
  foreach ($entities as $type => $bundles) {
    $properties =& $info[$type]['properties'];
    $properties['salesforce_mapping_object'] = array(
      'label' => t("Salesforce mapping object"),
      'type' => 'salesforce_mapping_object',
      'description' => t("Salesforce mapping object"),
      'getter callback' => 'salesforce_mapping_object_entity_property_get',
    );
  }
  return $info;
}

/**
 * Implements hook_menu().
 */
function salesforce_mapping_menu() {
  $items = array();
  $items['admin/content/salesforce'] = array(
    'title' => 'Salesforce Mapped Objects',
    'description' => 'Manage mapped Salesforce objects.',
    'type' => MENU_LOCAL_TASK,
    'page callback' => 'salesforce_mapping_object_overview_page',
    'file' => 'includes/salesforce_mapping_object.admin.inc',
    'access arguments' => array(
      'view salesforce mapping object',
    ),
  );

  // Define SF activity local tasks for all mapped entities.
  $defaults = array(
    'file' => 'salesforce_mapping_object.admin.inc',
    'file path' => drupal_get_path('module', 'salesforce_mapping') . '/includes',
  );
  $mappings = salesforce_mapping_load();
  $mapped_entities = array();
  foreach ($mappings as $mapping) {

    // We grab the bundle now because it becomes inaccessible for some entities
    // after it is put into the loop below:
    $mapped_entities[$mapping->drupal_entity_type] = $mapping->drupal_bundle;
  }
  $manual_uris = array();
  drupal_alter('salesforce_mapping_entity_uris', $manual_uris);
  foreach ($mapped_entities as $type => $bundle) {
    $uri = array();
    if (isset($manual_uris[$type])) {
      $uri = $manual_uris[$type];
    }
    else {
      try {
        $info = entity_get_info($type);
        $bundle_key = $info['entity keys']['bundle'] ?: 'type';
        $entity = entity_create($type, array(
          $bundle_key => $bundle,
        ));
        $uri = method_exists($entity, 'uri') ? $entity
          ->uri() : entity_uri($type, $entity);
      } catch (Exception $e) {

        // Fall through to default behavior
      }
    }
    if (empty($uri['path'])) {
      $path = 'admin/content/salesforce/' . $type . '/%' . $type . '/salesforce_activity';
      $menu_type = MENU_NORMAL_ITEM;
    }
    else {
      $path = $uri['path'] . '%' . $type . '/salesforce_activity';
      $menu_type = MENU_LOCAL_TASK;
    }
    $entity_arg = substr_count($path, '/') - 1;
    $items[$path] = array(
      'title' => 'Salesforce activity',
      'description' => 'View Salesforce activity for this entity.',
      'type' => $menu_type,
      'page callback' => 'salesforce_mapping_object_view',
      'page arguments' => array(
        $entity_arg,
        $type,
      ),
      'access callback' => 'salesforce_mapping_entity_mapping_accessible',
      'access arguments' => array(
        'view',
        $entity_arg,
        $type,
      ),
    );
    $items[$path . '/view'] = array(
      'title' => 'View',
      'type' => MENU_DEFAULT_LOCAL_TASK,
      'weight' => -10,
    );
    $items[$path . '/edit'] = array(
      'page callback' => 'salesforce_mapping_object_edit',
      'page arguments' => array(
        $entity_arg,
        $type,
      ),
      'access arguments' => array(
        'edit salesforce mapping object',
      ),
      'title' => 'Edit',
      'type' => MENU_LOCAL_TASK,
      'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
    ) + $defaults;
    $items[$path . '/delete'] = array(
      'page callback' => 'drupal_get_form',
      'page arguments' => array(
        'salesforce_mapping_object_delete_form',
        $entity_arg,
        $type,
      ),
      'access arguments' => array(
        'delete salesforce mapping object',
      ),
      'title' => 'Delete',
      'type' => MENU_LOCAL_TASK,
      'context' => MENU_CONTEXT_INLINE,
    );
  }

  // Provide a default Delete location, in case a mapping gets orphaned.
  $items['admin/content/salesforce/%/delete'] = array(
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'salesforce_mapping_universal_object_delete_form',
      3,
    ),
    'access arguments' => array(
      'delete salesforce mapping object',
    ),
    'title' => 'Delete',
    'type' => MENU_NORMAL_ITEM,
    'context' => MENU_CONTEXT_INLINE,
  );
  return $items;
}

/**
 * Implements hook_salesforce_mapping_entity_uris_alter().
 *
 * Node and User, like most entities in core, don't respond well to entity_uri()
 * calls on unsaved entity stubs, which is what we need for our menu items.
 */
function salesforce_mapping_salesforce_mapping_entity_uris_alter(&$entity_uris) {
  $entity_uris['node'] = array(
    'path' => 'node/',
  );
  $entity_uris['user'] = array(
    'path' => 'user/',
  );
  $entity_uris['taxonomy_term'] = array(
    'path' => 'taxonomy/term/',
  );
  $entity_uris['relation'] = array(
    'path' => 'relation/',
  );
}

/**
 * Loads a single salesforce_mapping or all of them if no name provided.
 *
 * @param null $name
 *   Name of the map to load.
 *
 * @return array
 *   The requested mapping or all of them if no one specific was requested.
 */
function salesforce_mapping_load($name = NULL) {
  $types = entity_load_multiple_by_name('salesforce_mapping', isset($name) ? array(
    $name,
  ) : FALSE);
  return isset($name) ? reset($types) : $types;
}

/**
 * Loads multiple salesforce_mappings based on a set of matching conditions.
 *
 * @param array $properties
 *   An array of properties on the {salesforce_mapping} table in the form
 *     'field' => $value.
 * @param bool $reset
 *   Whether to reset the internal contact loading cache.
 *
 * @return array
 *   An array of salesforce_mapping objects.
 */
function salesforce_mapping_load_multiple($properties = array(), $reset = FALSE) {
  $mappings = array();
  $efq = new EntityFieldQuery();
  $efq
    ->entityCondition('entity_type', 'salesforce_mapping');
  $record_type = NULL;
  foreach ($properties as $key => $value) {
    if ($key == 'salesforce_record_type') {
      $record_type = $value;
    }
    else {
      $efq
        ->propertyCondition($key, $value);
    }
  }
  $efq
    ->propertyOrderBy('weight');
  $results = $efq
    ->execute();
  if (!empty($results)) {
    $salesforce_mapping_ids = array_keys($results['salesforce_mapping']);
    if (!empty($salesforce_mapping_ids)) {
      $mappings = entity_load('salesforce_mapping', $salesforce_mapping_ids, array(), $reset);
    }
    if ($record_type) {
      foreach ($mappings as $id => $mapping) {
        if (empty($mapping->salesforce_record_types_allowed[$record_type])) {
          unset($mappings[$id]);
        }
      }
    }
  }
  return $mappings;
}

/**
 * Implements hook_theme().
 */
function salesforce_mapping_theme($existing, $type, $theme, $path) {
  return array(
    'salesforce_fieldmap_form_table' => array(
      'render element' => 'elements',
      'file' => 'includes/salesforce_mapping.admin.inc',
    ),
    'salesforce_mapping_overview_tabledrag_form' => array(
      'render element' => 'form',
      'file' => 'includes/salesforce_mapping.ui_controller.inc',
    ),
    'salesforce_mapping_form_table_row' => array(
      'render element' => 'elements',
      'file' => 'includes/salesforce_mapping.admin.inc',
    ),
  );
}

/**
 * Display a salesforce object mapping.
 *
 * @param Entity $entity
 *   The mapped Entity.
 * @param String $type
 *   The mapped Entity's Type.
 *
 * @return array
 *   Render array.
 */
function salesforce_mapping_object_view($entity, $type, $view_mode = 'full') {
  $entity_wrapper = entity_metadata_wrapper($type, $entity);
  $sf_mapping_object = $entity_wrapper->salesforce_mapping_object
    ->value();
  if ($sf_mapping_object) {
    return $sf_mapping_object
      ->view($view_mode);
  }
  else {

    // @todo: can we show old revisions here if they exist?
    return array(
      'info' => array(
        '#markup' => t('This entity is not mapped to Salesforce. Click "Edit" to force mapping.'),
      ),
    );
  }
}

/**
 * Edit a salesforce object mapping based only on the object.
 *
 * @param Entity $entity
 *   The mapped Entity.
 * @param String $type
 *   The mapped Entity's Type.
 *
 * @return array
 *   Render array.
 */
function salesforce_mapping_object_edit($entity, $type) {
  $entity_wrapper = entity_metadata_wrapper($type, $entity);
  $sf_mapping_object = $entity_wrapper->salesforce_mapping_object
    ->value();
  return drupal_get_form('salesforce_mapping_object_form', $sf_mapping_object, $type, $entity_wrapper
    ->getIdentifier());
}

/**
 * Delete a salesforce object mapping based only on the object.
 *
 * @param Entity $entity
 *   The mapped Entity.
 * @param string $type
 *   The mapped Entity's Type.
 *
 * @return array
 *   Render array.
 */
function salesforce_mapping_object_delete_form($form, &$form_state, Entity $entity, $type) {
  $entity_wrapper = entity_metadata_wrapper($type, $entity);
  $sf_mapping_object = $entity_wrapper->salesforce_mapping_object
    ->value();
  $form_state['salesforce_mapping_object'] = $sf_mapping_object;
  $form['#submit'][] = 'salesforce_mapping_object_delete_form_submit';
  $form = confirm_form($form, t('Are you sure you want to delete the mapping from !entity_label to Salesforce object %sf_id?', array(
    '!entity_label' => $entity_wrapper
      ->label(),
    '%sf_id' => $sf_mapping_object->salesforce_id,
  )), entity_uri('salesforce_mapping_object', $sf_mapping_object), '<p>' . t('Deleting this link cannot be undone.') . '</p>', t('Delete'), t('Cancel'), 'confirm');
  return $form;
}

/**
 * Delete a salesforce object mapping based only on the SFID.
 *
 * @param string $sfid
 *   SFID for the mapping.
 *
 * @return array
 *   Render array.
 */
function salesforce_mapping_universal_object_delete_form($form, &$form_state, $sfid) {
  $sf_mapping_object = salesforce_mapping_object_load_by_sfid($sfid);
  if (!$sf_mapping_object) {
    drupal_set_message(t('No mapping found for SF ID %sfid', array(
      '%sfid' => $sfid,
    )), 'warning');
    return $form;
  }
  $type = $sf_mapping_object->entity_type;
  $entity = entity_load_single($sf_mapping_object->entity_type, $sf_mapping_object->entity_id);
  if ($entity) {
    $entity_wrapper = entity_metadata_wrapper($type, $entity);
  }
  else {
    $entity_wrapper = NULL;
  }
  $form_state['salesforce_mapping_object'] = $sf_mapping_object;
  $form['#submit'][] = 'salesforce_mapping_object_delete_form_submit';
  $form = confirm_form($form, t('Are you sure you want to delete the mapping from !entity_label to Salesforce object %sf_id?', array(
    '!entity_label' => $entity_wrapper ? $entity_wrapper
      ->label() : t('(missing entity)'),
    '%sf_id' => $sf_mapping_object->salesforce_id,
  )), entity_uri('salesforce_mapping_object', $sf_mapping_object), '<p>' . t('Deleting this link cannot be undone.') . '</p>', t('Delete'), t('Cancel'), 'confirm');
  return $form;
}

/**
 * Submit callback for salesforce_mapping_object_delete_form().
 */
function salesforce_mapping_object_delete_form_submit($form, &$form_state) {
  $sfm_object = $form_state['salesforce_mapping_object'];
  $result = entity_delete('salesforce_mapping_object', $sfm_object->salesforce_mapping_object_id);
  if ($result === FALSE) {
    drupal_set_message(t('Object could not be deleted.'), 'error');
  }
  else {
    drupal_set_message(t('Link has been deleted.'));
    watchdog('salesforce', 'Deleted object link', array(), WATCHDOG_NOTICE);
    $form_state['redirect'] = 'admin/content/salesforce';
  }
}

/**
 * Return a Salesforce Mapping Object.
 *
 * @see entity_load()
 */
function salesforce_mapping_object_load($salesforce_mapping_object_id, $conditions = array(), $reset = FALSE) {
  if (!is_bool($salesforce_mapping_object_id)) {
    $salesforce_mapping_object_id = array(
      $salesforce_mapping_object_id,
    );
  }
  $objects = entity_load('salesforce_mapping_object', $salesforce_mapping_object_id, $conditions, $reset);
  return $objects ? reset($objects) : FALSE;
}

/**
 * Returns Salesforce object mappings for a given Drupal entity.
 *
 * @param string $entity_type
 *   Type of entity to load.
 * @param int $entity_id
 *   Unique identifier of the target entity to load.
 * @param bool $reset
 *   Whether or not the cache should be cleared and fetch from current data.
 *
 * @return SalesforceMappingObject
 *   The requested SalesforceMappingObject or FALSE if none was found.
 */
function salesforce_mapping_object_load_by_drupal($entity_type, $entity_id, $reset = FALSE) {
  $conditions = array(
    'entity_id' => $entity_id,
    'entity_type' => $entity_type,
  );
  return salesforce_mapping_object_load(FALSE, $conditions, $reset);
}

/**
 * Return Salesforce object mappings for a given Salesforce object.
 *
 * @param string $salesforce_id
 *   Unique Id provided by Salesforce for the Salesforce record.
 * @param bool $reset
 *   Whether to reset the cache and retrieve a new record.
 *s
 * @return array
 *   Entities that match the given $salesforce_id.
 */
function salesforce_mapping_object_load_by_sfid($salesforce_id, $reset = FALSE) {
  $conditions = array(
    'salesforce_id' => $salesforce_id,
  );
  return salesforce_mapping_object_load(FALSE, $conditions, $reset);
}

/**
 * Return a unique list of mapped Salesforce object types.
 *
 * @TODO: add parameter to limit by trigger: http://drupal.org/node/1915668
 */
function salesforce_mapping_get_mapped_objects() {
  $object_types = array();
  $mappings = salesforce_mapping_load();
  usort($mappings, 'salesforce_mapping_sort');
  foreach ($mappings as $mapping) {
    $object_types[$mapping->salesforce_object_type] = $mapping->salesforce_object_type;
  }
  return $object_types;
}

/**
 * Return a unique list of mapped Drupal entity types and bundles.
 */
function salesforce_mapping_get_mapped_entities() {
  $entity_types = array();
  $mappings = salesforce_mapping_load();
  usort($mappings, 'salesforce_mapping_sort');
  foreach ($mappings as $mapping) {
    $entity_types[$mapping->drupal_entity_type][$mapping->drupal_bundle] = TRUE;
  }
  return $entity_types;
}

/**
 * Sort mappings by weight.
 */
function salesforce_mapping_sort($mapping_a, $mapping_b) {
  if ($mapping_a->weight == $mapping_b->weight) {
    return 0;
  }
  return $mapping_a->weight < $mapping_b->weight ? -1 : 1;
}

/**
 * Implements hook_entity_delete().
 */
function salesforce_mapping_entity_delete($entity, $type) {

  // Delete any Salesforce object mappings with this entity.
  list($entity_id, , $bundle) = entity_extract_ids($type, $entity);
  $mapping_object = salesforce_mapping_object_load_by_drupal($type, $entity_id);

  // No mapping object for this entity, return.
  if (!$mapping_object) {
    return;
  }

  // Only delete the mapping object if it won't be handled by the delete
  // trigger in the mapping. We're avoiding the issue of deleting a mapping
  // object before deleting the mapped object.
  $mappings = salesforce_mapping_load_multiple(array(
    'drupal_entity_type' => $type,
    'drupal_bundle' => $bundle,
  ));
  foreach ($mappings as $mapping) {

    // Look for any mapping with the delete trigger enabled.
    if ($mapping->sync_triggers & SALESFORCE_MAPPING_SYNC_DRUPAL_DELETE) {
      return;
    }
  }

  // No mappings have the delete hook enabled, go ahead and delete the mapping
  // object.
  $mapping_object
    ->delete();
}

/**
 * Implements hook_permission().
 */
function salesforce_mapping_permission() {
  return array(
    'administer salesforce mapping' => array(
      'title' => t('Administer Salesforce mapping'),
      'description' => t('Administer Salesforce field maps.'),
      'restrict access' => TRUE,
    ),
    'view salesforce mapping object' => array(
      'title' => t('View Salesforce mapping object'),
      'description' => t('View Salesforce mapping data.'),
    ),
    'create salesforce mapping object' => array(
      'title' => t('Create Salesforce mapping object'),
      'description' => t('Allows a user to create Salesforce mapping object entities.'),
      'restrict access' => TRUE,
    ),
    'edit salesforce mapping object' => array(
      'title' => t('Edit Salesforce mapping object'),
      'description' => t('Allows a user to edit Salesforce mapping object entities.'),
      'restrict access' => TRUE,
    ),
    'delete salesforce mapping object' => array(
      'title' => t('Delete Salesforce mapping object'),
      'description' => t('Allows a user to delete Salesforce mapping object entities.'),
      'restrict access' => TRUE,
    ),
  );
}

/**
 * Check access permission for Mapped Object Entity UI.
 */
function salesforce_mapping_object_access($op, $salesforce_mapping_object = NULL, $account = NULL) {
  switch ($op) {
    case 'view':
      return user_access('view salesforce mapping object', $account);
    case 'create':
      return user_access('create salesforce mapping object', $account);
    case 'edit':
    case 'update':
      return user_access('edit salesforce mapping object', $account);
    case 'delete':
      return user_access('delete salesforce mapping object', $account);
  }
  return FALSE;
}
function salesforce_mapping_entity_mapping_accessible($op, $entity, $type, $account = NULL) {
  $wrapper = entity_metadata_wrapper($type, $entity);
  return salesforce_mapping_object_access($op, $wrapper->salesforce_mapping_object, $account);
}

/**
 * Implements hook_entity_update().
 *
 * Ensures drupal entity has an update timestamp.
 */
function salesforce_mapping_entity_update($entity, $type) {

  // Check if mapping exists.
  $sf_mappings = salesforce_mapping_load_multiple(array(
    'drupal_entity_type' => $type,
  ));
  if ($sf_mappings) {
    list($entity_id) = entity_extract_ids($type, $entity);
    $sf_mapping_object = salesforce_mapping_object_load_by_drupal($type, $entity_id);
    if ($sf_mapping_object) {

      // Update entity updated property.
      $sf_mapping_object->entity_updated = REQUEST_TIME;

      // No new revision needed for this change. If this generates a push, then
      // a revision will be generated for that action.
      $sf_mapping_object->is_new_revision = FALSE;
      $sf_mapping_object
        ->save();
    }
  }
}

/**
 * Get the Salesforce fieldmap types array.
 *
 * @see hook_salesforce_mapping_fieldmap_type()
 * @see hook_salesforce_mapping_fieldmap_type_alter()
 *
 * @param string $fieldmap_type
 *   The fieldmap type, e.g. property, for which the info shall be returned, or
 *   NULL to return an array with info about all types.
 */
function salesforce_mapping_get_fieldmap_types($fieldmap_type = NULL) {

  // Use the advanced drupal_static() pattern, since this is called very often.
  static $drupal_static_fast;
  if (!isset($drupal_static_fast)) {
    $drupal_static_fast['salesforce_mapping_fieldmap_type'] =& drupal_static(__FUNCTION__);
  }
  $salesforce_mapping_fieldmap_type =& $drupal_static_fast['salesforce_mapping_fieldmap_type'];
  if (empty($salesforce_mapping_fieldmap_type)) {
    if ($cache = cache_get('salesforce_mapping_fieldmap_type')) {
      $salesforce_mapping_fieldmap_type = $cache->data;
    }
    else {
      $salesforce_mapping_fieldmap_type = module_invoke_all('salesforce_mapping_fieldmap_type');

      // Let other modules alter the fieldmap type.
      drupal_alter('salesforce_mapping_fieldmap_type', $salesforce_mapping_fieldmap_type);
      cache_set('salesforce_mapping_fieldmap_type', $salesforce_mapping_fieldmap_type);
    }
  }
  if (empty($fieldmap_type)) {
    return $salesforce_mapping_fieldmap_type;
  }
  elseif (isset($salesforce_mapping_fieldmap_type[$fieldmap_type])) {
    return $salesforce_mapping_fieldmap_type[$fieldmap_type];
  }
}

/**
 * Callback to get $salesforce_mapping_object->salesforce_url.
 */
function salesforce_mapping_object_property_salesforce_url_get(SalesforceMappingObject $salesforce_mapping_object, array $options, $property_name, $entity_type) {
  $sfapi = salesforce_get_api();
  if ($sfapi) {
    $sf_object_link = $sfapi
      ->getInstanceUrl() . '/' . $salesforce_mapping_object->salesforce_id;
  }
  else {
    $sf_object_link = NULL;
  }
  return $sf_object_link;
}

/**
 * Callback to get $salesforce_mapping_object->entity.
 */
function salesforce_mapping_object_property_entity_get(SalesforceMappingObject $salesforce_mapping_object, array $options, $property_name, $entity_type) {
  $entity = entity_load_single($salesforce_mapping_object->entity_type, $salesforce_mapping_object->entity_id);
  if ($entity) {
    return entity_metadata_wrapper($salesforce_mapping_object->entity_type, $entity);
  }
  return FALSE;
}

/**
 * Callback to set $salesforce_mapping_object->entity.
 */
function salesforce_mapping_object_property_entity_set(SalesforceMappingObject $salesforce_mapping_object, $name, $value, $lang, $type, $info) {
  $salesforce_mapping_object->entity_type = $value
    ->type();
  $salesforce_mapping_object->entity_id = $value
    ->getIdentifier();
}

/**
 * Callback to get the salesforce mapping object for an entity.
 */
function salesforce_mapping_object_entity_property_get($entity, array $options, $property_name, $entity_type) {
  $mapping_object = salesforce_mapping_object_load_by_drupal($entity_type, entity_id($entity_type, $entity));
  if ($mapping_object) {
    return entity_metadata_wrapper('salesforce_mapping_object', $mapping_object);
  }
  return FALSE;
}

/**
 * Return loaded mapping objects from a query.
 *
 * @param array $header
 *   Table sort header array.
 * @param array $properties
 *   Array of properties to include in the query.
 * @param int $limit
 *   Number of results to return.
 * @param int $mapping_id
 *   Entity ID for the mapping: limits results to a single mapping.
 *
 * @return array
 *   Array of loaded entities.
 */
function salesforce_mapping_object_filter_query($header = FALSE, $properties = array(), $limit = 25, $mapping_id = NULL) {
  $table = 'salesforce_mapping_object';
  $id = 'salesforce_mapping_object_id';
  if ($mapping_id) {
    $table .= '_revision';
    $id = 'revision_id';
  }
  $limit = !empty($limit) ? $limit : 25;
  $query = db_select($table, 'm')
    ->extend('PagerDefault')
    ->extend('TableSort')
    ->fields('m')
    ->limit($limit)
    ->orderByHeader($header);
  if (!$mapping_id) {
    $query
      ->join($table . '_revision', 'r', 'm.salesforce_mapping_object_id = r.salesforce_mapping_object_id');
    $query
      ->groupBy('m.salesforce_mapping_object_id');

    // Add count columns for each status value.
    foreach (salesforce_mapping_object_sync_status() as $status_id => $status) {
      $query
        ->addExpression('count(CASE WHEN r.last_sync_status = ' . $status_id . ' THEN TRUE ELSE NULL END)', 'status_' . $status_id);
    }
  }
  else {
    $query
      ->condition('m.salesforce_mapping_object_id', $mapping_id);
  }

  // Add conditions.
  foreach ($properties as $property => $value) {
    if (isset($value) && $value != '') {
      $operator = is_array($value) ? 'IN' : '=';
      switch ($property) {
        case 'last_sync':

          // Handle from/to.
          if (!empty($value['from'])) {
            $query
              ->condition('m.' . $property, strtotime($value['from']), '>=');
          }
          if (!empty($value['to'])) {
            $query
              ->condition('m.' . $property, strtotime($value['to']), '<=');
          }
          break;
        case 'salesforce_id':
          if (strlen($value) < 18) {

            // Match start of the Salesforce ID if less than the full 18 chars.
            $operator = 'LIKE';
            $value = db_like($value) . '%';
          }
        default:
          $query
            ->condition('m.' . $property, $value, $operator);
      }
    }
  }
  $results = $query
    ->execute()
    ->fetchAllAssoc($id);
  return $results;
}

/**
 * Definition of allowed sync statuses. Integer keyed array.
 *
 * @return array
 *   Associative array of statuses keyed by integer.
 */
function salesforce_mapping_object_sync_status() {
  $statuses = array(
    SALESFORCE_MAPPING_STATUS_ERROR => t('Error'),
    SALESFORCE_MAPPING_STATUS_SUCCESS => t('Success'),
  );
  return $statuses;
}

/**
 * Helper method to return human readable versions of mapping properties.
 *
 * @param SalesforceMappingObject $mapping
 *   Fully loaded mapping object.
 * @param string $name
 *   Property name.
 * @param string $property
 *   Property value.
 *
 * @return string
 *   Property value.
 */
function salesforce_mapping_object_render_property($mapping, $name, $property) {
  $value = $property
    ->value();
  if ($value == '' or $value == NULL) {
    return '';
  }
  switch ($name) {
    case 'salesforce_id':
      $salesforce_url = $mapping->salesforce_url
        ->value();
      if ($salesforce_url) {
        $content = l($mapping->salesforce_id
          ->value(), $salesforce_url, array(
          'attributes' => array(
            'target' => '_blank',
          ),
        ));
      }
      else {
        $content = $mapping->salesforce_id
          ->value();
      }
      break;
    case 'created':
    case 'last_sync':
    case 'entity_updated':
      $content = format_date($property
        ->value());
      break;
    case 'last_sync_status':
      $statuses = salesforce_mapping_object_sync_status();
      $content = isset($statuses[$property
        ->value()]) ? $statuses[$property
        ->value()] : NULL;
      break;
    case 'last_sync_action':
      $content = drupal_ucfirst($property
        ->value());
      break;
    case 'entity':
      if ($uri = entity_uri($property
        ->type(), $property
        ->value())) {
        $content = l($property
          ->label(), $uri['path'], $uri['options']);
      }
      else {
        $content = check_plain($property
          ->label());
      }
      break;
    case 'entity_type':

      // Get human readable entity label.
      $entity_info = entity_get_info($property
        ->value());
      $content = $entity_info['label'];
      break;
    case 'entity_id':
    case 'last_sync_message':
      $content = check_plain($property
        ->value());
      break;
    default:
      $content = $property
        ->value();
  }
  return $content;
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function salesforce_mapping_form_salesforce_settings_form_alter(&$form, &$form_state, $form_id) {
  $form['sf_object_filters'] = array(
    '#type' => 'fieldset',
    '#title' => t('Salesforce object filters'),
    '#weight' => 5,
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
    '#description' => t('Allows you to limit which objects show up in the "Salesforce object" dropdown on the Salesforce mapping form.'),
    '#prefix' => l('', '', array(
      'attributes' => array(
        'name' => 'sf_object_filters_anchor',
      ),
      'external' => TRUE,
    )),
  );
  $form['sf_object_filters']['salesforce_limit_to_triggerable'] = array(
    '#type' => 'checkbox',
    '#title' => t('Only show triggerable Salesforce objects'),
    '#description' => t('When pulling in a list of Salesforce objects to map, only show ones with the property "triggerable"'),
    '#default_value' => variable_get('salesforce_limit_to_triggerable', TRUE),
  );
  $form['sf_object_filters']['salesforce_limit_to_updateable'] = array(
    '#type' => 'checkbox',
    '#title' => t('Only show updateable Salesforce objects'),
    '#description' => t('When pulling in a list of Salesforce objects to map, only show ones with the property "updateable"'),
    '#default_value' => variable_get('salesforce_limit_to_updateable', TRUE),
  );
}

Functions

Namesort descending Description
salesforce_mappings_access Access callback for managing Salesforce mappings.
salesforce_mapping_entity_delete Implements hook_entity_delete().
salesforce_mapping_entity_info Implements hook_entity_info().
salesforce_mapping_entity_mapping_accessible
salesforce_mapping_entity_property_info Implements hook_entity_property_info().
salesforce_mapping_entity_update Implements hook_entity_update().
salesforce_mapping_form_salesforce_settings_form_alter Implements hook_form_FORM_ID_alter().
salesforce_mapping_get_fieldmap_types Get the Salesforce fieldmap types array.
salesforce_mapping_get_mapped_entities Return a unique list of mapped Drupal entity types and bundles.
salesforce_mapping_get_mapped_objects Return a unique list of mapped Salesforce object types.
salesforce_mapping_load Loads a single salesforce_mapping or all of them if no name provided.
salesforce_mapping_load_multiple Loads multiple salesforce_mappings based on a set of matching conditions.
salesforce_mapping_menu Implements hook_menu().
salesforce_mapping_object_access Check access permission for Mapped Object Entity UI.
salesforce_mapping_object_delete_form Delete a salesforce object mapping based only on the object.
salesforce_mapping_object_delete_form_submit Submit callback for salesforce_mapping_object_delete_form().
salesforce_mapping_object_edit Edit a salesforce object mapping based only on the object.
salesforce_mapping_object_entity_property_get Callback to get the salesforce mapping object for an entity.
salesforce_mapping_object_filter_query Return loaded mapping objects from a query.
salesforce_mapping_object_load Return a Salesforce Mapping Object.
salesforce_mapping_object_load_by_drupal Returns Salesforce object mappings for a given Drupal entity.
salesforce_mapping_object_load_by_sfid Return Salesforce object mappings for a given Salesforce object.
salesforce_mapping_object_property_entity_get Callback to get $salesforce_mapping_object->entity.
salesforce_mapping_object_property_entity_set Callback to set $salesforce_mapping_object->entity.
salesforce_mapping_object_property_salesforce_url_get Callback to get $salesforce_mapping_object->salesforce_url.
salesforce_mapping_object_render_property Helper method to return human readable versions of mapping properties.
salesforce_mapping_object_sync_status Definition of allowed sync statuses. Integer keyed array.
salesforce_mapping_object_view Display a salesforce object mapping.
salesforce_mapping_page_alter Implements hook_page_alter().
salesforce_mapping_permission Implements hook_permission().
salesforce_mapping_salesforce_mapping_entity_uris_alter Implements hook_salesforce_mapping_entity_uris_alter().
salesforce_mapping_sort Sort mappings by weight.
salesforce_mapping_theme Implements hook_theme().
salesforce_mapping_universal_object_delete_form Delete a salesforce object mapping based only on the SFID.

Constants