Web Dev

Mapping Salesforce Object fields to Drupal Taxonomy terms

The Salesforce Suite module for Drupal synchronizes Salesforce Objects with Drupal Content Types on a one-to-one, field-to-field basis.

However, it doesn’t map an Object’s fields to a Content Type’s Taxonomy terms. After laying out a use case, I’ll share my working solution.

Example

Let’s say you want to replicate Salesforce Contact Objects as instances of a Drupal Content Type.

The following Object fields map directly to fields in our Content Type.

  • Name
  • LeadSource
  • Email

You could create a Content Type mirroring those as simple text fields. But, I have something more interesting in mind for you!

i-NPS57xN-M

LeadSource is a Salesforce picklist that might work well as a Drupal Taxonomy. Perhaps you’d like to use it in a faceted search, or as an easy filter for a view, or use some cool module for taxonomies? Sorry, the Salesforce module can’t get you there out of the box.

The Road Taken

In August of 2013, the user mkryemadhi posted a Drupal.org issue titled Mapping drupal vocabulary terms with Salesforce field inquiring whether or not it was possible. A few others replied, also in search of a solution. About a year later, one of the module’s contributors, tauno, replied with a suggestion.

… For pulling, you would need to implement hook_salesforce_pull_entity_value_alter() to use a term name from SF and convert that to a term id in Drupal.

A custom field mapping handler could be implemented to make this all possible from the UI. Moving to the Feature Request queue.

My Solution

Here’s how I used the first part of that advice and implemented hook_salesforce_pull_entity_value_alter() to successfully map Salesforce Object fields to Drupal Taxonomy terms.

To start, I created a custom module with a function implementing the hook. Then, because I had more than one implementation of that kind, I checked the incoming Object type. If it wasn’t Contact, I skipped it. Otherwise, I used the Content Type’s mapped field to obtain the Vocabulary and either create a new term or use the existing one.

i-WTtmWMx-M

To use my solution, you’ll need to:

  • Have a Content Type with a field of type Term reference.
  • Create and enable a custom module containing my code, below.
  • Set up a mapping from the Content Type’s field (“Drupal Field”) using Related entities, as above, to the Object’s field (“Salesforce Field”).

But, first: please note the following:

  • Expect some naive Drupal / PHP mistakes. This is an excerpt from my very first Drupal module / PHP code.
  • This solution hijacks the module’s concept of Related Entity; the way I went about it prevents its original, intended usage. (It’s meant more for referencing a Node from another Node.)
  • I should have used a custom mapping handler and created a proper UI for it.

In the near future I hope to resolve the deficiencies in my implementation and contribute my solution back to Drupal’s Salesforce Suite community.

Code

<?php

/**
 * Implementation of hook_salesforce_pull_entity_value_alter()
 * @author Mike Christianson <http://codeaweso.me/2015/04/mapping-salesforce-object-fields-to-drupal-taxonomy-terms/>	
 */
function codeawesome_salesforce_pull_entity_value_alter(&$value, $field_map, $sf_object) {
  $sf_type = $sf_object['attributes']['type'];
  if ($sf_type !== 'Contact') {
    return;
  }
  if (is_related_entity($field_map)) {
    handle_related_entity($value, $field_map, $sf_object);
  }
}

/**
 * @param $field_map
 * @return bool
 */
function is_related_entity($field_map) {
  return $field_map['drupal_field']['fieldmap_type'] == 'related_entity';
}

/**
 * @param $value
 * @param $field_map
 * @param $sf_object
 */
function handle_related_entity(&$value, $field_map, $sf_object) {
  $field_info_field = get_drupal_field_info($field_map);
  $vocabulary = load_vocabulary($field_info_field);
  if (isset($vocabulary)) {
    $sf_picklist_str = get_sf_field_value($field_map, $sf_object);
    if (!empty($sf_picklist_str)) {
      $sf_picklist_values = explode(SALESFORCE_MAPPING_ARRAY_DELIMITER, $sf_picklist_str);
      $terms = array();
      foreach ($sf_picklist_values as $picklist_value) {
        $term = create_or_load_term($picklist_value, $vocabulary);
        if (isset($term)) {
          $terms[] = $term;
        }
      }
      $value = make_array_of_term_ids($terms);
      if ($field_info_field['cardinality'] == 1) {
        $value = reset($value);
      }
    }
  }
}

/**
 * @param $field_map
 * @return bool|mixed|void
 */
function get_drupal_field_info($field_map) {
  $druapl_field = get_drupal_field_name($field_map);
  return field_info_field($druapl_field);
}

/**
 * @param $field_info_field
 * @return mixed
 */
function load_vocabulary($field_info_field) {
  $vocabulary = null;
  $vocabularyName = $field_info_field['settings']['allowed_values'][0]['vocabulary'];
  if (isset($vocabularyName)) {
    $vocabulary = taxonomy_vocabulary_machine_name_load($vocabularyName);
  }
  return $vocabulary;
}

function get_sf_field_value($field_map, $sf_object) {
  $sf_field = $field_map['salesforce_field']['name'];
  $sf_value = $sf_object[$sf_field];
  return $sf_value;
}

/**
 * @param $picklist_value
 * @param $vocabulary
 * @return array|mixed|null
 */
function create_or_load_term($picklist_value, $vocabulary) {
  $term = null;

  if (!empty($picklist_value)) {
    $existing_terms = taxonomy_get_term_by_name($picklist_value, $vocabulary->machine_name);

    if (empty($existing_terms)) {
      $term = create_new_term($vocabulary, $picklist_value);
    } else {
      $term = reset($existing_terms);
    }
  }

  return $term;
}

/**
 * @param $terms
 * @return array
 */
function make_array_of_term_ids($terms)
{
  $term_ids = array();
  foreach ($terms as $new_term) {
    $term_ids[] = $new_term->tid;
  }
  return $term_ids;
} 
Reference: Mapping Salesforce Object fields to Drupal Taxonomy terms from our WCG partner Mike Christianson at the CodeAwesome blog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Trinity
Trinity
8 years ago

Where is the function get_drupal_field_name() ?

Mike Christianson
8 years ago

@Trinity I accidentally left out the `get_drupal_field_name()` function. Unfortunately, I no longer have access to the original codebase and am unable to provide it. If you use a debugger, or use print statements, to inspect `$field_map`, you may be able to come up with your own version of `get_drupal_field_name()`.

See also https://github.com/MikeChristianson/MikeChristianson.github.io/issues/2

Back to top button