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
You could create a Content Type mirroring those as simple text fields. But, I have something more interesting in mind for you!
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.
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. |
Where is the function get_drupal_field_name() ?
@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