Skip to content

Commit

Permalink
- Issue #2223673 by ohthehugemanatee, pianomansam, aaronbauman: add "…
Browse files Browse the repository at this point in the history
…push" button to mapping object edit form to force update from drupal

- refactor salesforce_push_cron() to break early, reduce indentation level

- fix hook_salesforce_push_entity_allowed_by_mapping bug in salesforce_push_entity_crud() ("continue" vs "continue 2")

- adding return value for salesforce_push_entity_crud() towards eventually making it more granular, useful for other callers
  • Loading branch information
Aaron Bauman committed Sep 1, 2015
1 parent 776df06 commit 4acc573
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ function salesforce_mapping_object_form($form, &$form_state, $mapping_object = N
'submit' => array(
'#type' => 'submit',
'#value' => isset($mapping_object->salesforce_mapping_object_id) ? t('Update mapping') : t('Save mapping'),
'#submit' => array('salesforce_mapping_object_form_save_mapping_submit'),
'#validate' => array('salesforce_mapping_object_form_save_mapping_validate')
),
);
if ($mapping_object && empty($mapping_object->is_new)) {
Expand Down Expand Up @@ -93,57 +95,40 @@ function salesforce_mapping_object_form_validate($form, &$form_state) {
}
}
$mapping = reset($mappings);

// Convert to 18-char if 15-char ID was given.
$values['salesforce_id'] = Salesforce::convertId($values['salesforce_id']);

// Check for existing mapping based on the Salesforce Id.
$mapping_object_sf = salesforce_mapping_object_load_by_sfid($values['salesforce_id'], TRUE);
$sf_object_type = $mapping->salesforce_object_type;

if ($mapping_object_sf &&
(empty($mapping_object->salesforce_mapping_object_id) || $mapping_object_sf->salesforce_mapping_object_id != $mapping_object->salesforce_mapping_object_id)) {
form_set_error('salesforce_id', t('Salesforce object is already mapped to a Drupal entity.'));
}

$sfapi = salesforce_get_api();
// Not authorized, we need to bail this time around.
if (!$sfapi->isAuthorized()) {
form_set_error('salesforce_id', t('Salesforce is not authorized.'));
}
}

// Attempt to retrieve the Salesforce object.
$sf_object = FALSE;
try {
$sf_object = $sfapi->objectRead($sf_object_type, $values['salesforce_id']);
}
catch (Exception $e) {
form_set_error('salesforce_id', t('Error getting object from Salesforce: @message', array('@message' => $e->getMessage())));
function salesforce_mapping_object_form_save_mapping_validate($form, &$form_state) {
if (empty($form_state['values']['salesforce_id'])) {
form_set_error('salesforce_id', t('Salesforce ID is required to save a new mapping.'));
}

if ($sf_object) {
// Use the returned Id to replace any 15 character Ids with the full 18
// character one.
$values['salesforce_id'] = $sf_object['Id'];

// Check for existing mapping based on the Salesforce Id.
$mapping_object_sf = salesforce_mapping_object_load_by_sfid($values['salesforce_id'], TRUE);

if ($mapping_object_sf &&
(empty($mapping_object->salesforce_mapping_object_id) || $mapping_object_sf->salesforce_mapping_object_id != $mapping_object->salesforce_mapping_object_id)) {
form_set_error('salesforce_id', t('Salesforce object is already mapped to a Drupal entity.'));
}

// Validate that Salesforce object is of an allowed type and record type.
$record_type = empty($sf_object['RecordTypeId']) ? 'default' : $sf_object['RecordTypeId'];

$record_type_allowed = FALSE;
foreach ($mappings as $mapping) {
if (in_array($record_type, $mapping->salesforce_record_types_allowed, TRUE)) {
$record_type_allowed = TRUE;
continue;
}
}

if (!$record_type_allowed) {
form_set_error('salesforce_id', t('Salesforce object record type is not allowed in any mappings.'));
}
$form_state['values']['salesforce_id'] = Salesforce::verifyId($form_state['values']['salesforce_id']);
if (strlen($form_state['values']['salesforce_id']) != 18) {
form_set_error('salesforce_id', t('Invalid Salesforce ID.'));
}
}

/**
* Implements hook_form_submit().
*/
function salesforce_mapping_object_form_submit($form, &$form_state) {
function salesforce_mapping_object_form_save_mapping_submit($form, &$form_state) {
$mapping_object = $form_state['salesforce_mapping_object'];
if (is_null($mapping_object)) {
$mapping_object = entity_create('salesforce_mapping_object', array(
Expand Down
153 changes: 89 additions & 64 deletions modules/salesforce_push/salesforce_push.module
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ function salesforce_push_entity_crud($entity_type, $entity, $sf_sync_trigger) {
// Avoid duplicate processing if this entity has just been updated by
// Salesforce pull.
if (isset($entity->salesforce_pull) && $entity->salesforce_pull) {
return;
return FALSE;
}

// Trigger a hook to allow other modules to prevent this entity/operation from
// triggering a sync with Salesforce.
foreach (module_implements('salesforce_push_entity_allowed') as $module) {
if (module_invoke($module, 'salesforce_push_entity_allowed', $entity_type, $entity, $sf_sync_trigger) === FALSE) {
return;
return FALSE;
}
}

Expand All @@ -66,7 +66,7 @@ function salesforce_push_entity_crud($entity_type, $entity, $sf_sync_trigger) {
// Allow other modules to prevent a sync per-mapping.
foreach (module_implements('salesforce_push_entity_allowed_by_mapping') as $module) {
if (module_invoke($module, 'salesforce_push_entity_allowed_by_mapping', $entity_type, $entity, $sf_sync_trigger, $mapping) === FALSE) {
continue;
continue 2;
}
}

Expand All @@ -86,6 +86,26 @@ function salesforce_push_entity_crud($entity_type, $entity, $sf_sync_trigger) {
}
}

function salesforce_push_form_salesforce_mapping_object_form_alter(&$form, &$form_state) {
$form['salesforce_id']['#required'] = FALSE;
$form['actions']['push'] = array(
'#type' => 'submit',
'#value' => t('Push'),
'#submit' => array('salesforce_push_mapping_object_form_submit'),
);
}

function salesforce_push_mapping_object_form_submit($form, &$form_state) {
$values = $form_state['values'];
$entity_type = $values['entity_type'];
$entity_id = $values['entity_id'];
$entity = entity_load_single($entity_type, $entity_id);
$trigger = SALESFORCE_MAPPING_SYNC_DRUPAL_UPDATE;
salesforce_push_entity_crud($entity_type, $entity, $trigger);
// @TODO we can do better than this:
// drupal_set_message('Push request submitted. If your mappings are set to push asynchronously, you need to run cron.');
}

/**
* Sync Drupal entities and Salesforce objects using the REST API.
*
Expand All @@ -107,7 +127,7 @@ function salesforce_push_sync_rest($entity_type, $entity, $mapping, $sf_sync_tri
}

list($entity_id) = entity_extract_ids($entity_type, $entity);
$mapping_object = salesforce_mapping_object_load_by_drupal($entity_type, $entity_id);
$mapping_object = salesforce_mapping_object_load_by_drupal($entity_type, $entity_id, TRUE);

// Delete SF object.
if ($sf_sync_trigger == SALESFORCE_MAPPING_SYNC_DRUPAL_DELETE) {
Expand Down Expand Up @@ -294,81 +314,85 @@ function salesforce_push_cron() {

$mapping_object = salesforce_mapping_object_load_by_drupal($entity_type, $entity_id);

if ($use_soap) {
if ($item->data['trigger'] == SALESFORCE_MAPPING_SYNC_DRUPAL_DELETE && $mapping_object) {
$delete_list[$delta] = $mapping_object->salesforce_id;
}
else {
$wrapper = entity_metadata_wrapper($item->data['entity_type'], $entity);
$params = salesforce_push_map_params($mapping, $wrapper, $key_field, $key_value, $use_soap);

$synced_entities[$delta] = array(
'entity_wrapper' => $wrapper,
'mapping_object' => $mapping_object,
'queue_item' => $item,
);

// Setup SF record type. CampaignMember objects get their type from
// their Campaign.
// @TODO: remove object-specific logic. Figure out how this works and implement generic support for recordtype inheritence, or objects that don't support recordtypes
if ($mapping->salesforce_record_type_default != SALESFORCE_MAPPING_DEFAULT_RECORD_TYPE
&& empty($params['RecordTypeId'])
&& ($mapping->salesforce_object_type != 'CampaignMember')) {
$params['RecordTypeId'] = $mapping->salesforce_record_type_default;
}
if (!$use_soap) { {
salesforce_push_sync_rest($entity_type, $entity, $mapping, $item->data['trigger']);
continue;
}

if ($item->data['trigger'] == SALESFORCE_MAPPING_SYNC_DRUPAL_DELETE && $mapping_object) {
$delete_list[$delta] = $mapping_object->salesforce_id;
continue;
}
$wrapper = entity_metadata_wrapper($item->data['entity_type'], $entity);
$params = salesforce_push_map_params($mapping, $wrapper, $key_field, $key_value, $use_soap);

$sobject = new stdClass();
$sobject->type = $mapping->salesforce_object_type;
foreach ($params as $key => $value) {
$sobject->fields[$key] = $value;
}
$synced_entities[$delta] = array(
'entity_wrapper' => $wrapper,
'mapping_object' => $mapping_object,
'queue_item' => $item,
);

if ($mapping_object && $mapping_object->salesforce_id) {
$sobject->Id = $mapping_object->salesforce_id;
$update_list[$delta] = $sobject;
}
else {
if ($key_field && $key_value) {
$upsert_list[$key_field][$delta] = $sobject;
}
else {
$create_list[$delta] = $sobject;
}
}
}
// Setup SF record type. CampaignMember objects get their type from
// their Campaign.
// @TODO: remove object-specific logic. Figure out how this works and implement generic support for recordtype inheritence, or objects that don't support recordtypes
if ($mapping->salesforce_record_type_default != SALESFORCE_MAPPING_DEFAULT_RECORD_TYPE
&& empty($params['RecordTypeId'])
&& ($mapping->salesforce_object_type != 'CampaignMember')) {
$params['RecordTypeId'] = $mapping->salesforce_record_type_default;
}

$sobject = new stdClass();
$sobject->type = $mapping->salesforce_object_type;
foreach ($params as $key => $value) {
$sobject->fields[$key] = $value;
}

// If we have a SFID, this is an update.
if ($mapping_object && $mapping_object->salesforce_id) {
$sobject->Id = $mapping_object->salesforce_id;
$update_list[$delta] = $sobject;
continue;
}

// If we have a dedupe key, prefer upsert.
if ($key_field && $key_value) {
$upsert_list[$key_field][$delta] = $sobject;
}
else {
salesforce_push_sync_rest($entity_type, $entity, $mapping, $item->data['trigger']);
// Otherwise create.
$create_list[$delta] = $sobject;
}

// Remove item from queue.
$queue->deleteItem($item);
$delta++;
}

if (!$use_soap) {
return;
}

// Use soap API to batch process records.
if ($use_soap) {
$soap = new SalesforceSoapPartner($sfapi);
if (!empty($delete_list)) {
$results = $soap->delete($delete_list);
salesforce_push_process_soap_results('Delete', $results, $synced_entities);
}
$soap = new SalesforceSoapPartner($sfapi);
if (!empty($delete_list)) {
$results = $soap->delete($delete_list);
salesforce_push_process_soap_results('Delete', $results, $synced_entities);
}

if (!empty($create_list)) {
$results = $soap->create($create_list);
salesforce_push_process_soap_results('Create', $results, $synced_entities);
}
if (!empty($create_list)) {
$results = $soap->create($create_list);
salesforce_push_process_soap_results('Create', $results, $synced_entities);
}

if (!empty($update_list)) {
$results = $soap->update($update_list);
salesforce_push_process_soap_results('Update', $results, $synced_entities);
}
if (!empty($update_list)) {
$results = $soap->update($update_list);
salesforce_push_process_soap_results('Update', $results, $synced_entities);
}

if (!empty($upsert_list)) {
foreach ($upsert_list as $key => $upsert_item) {
$results = $soap->upsert($key, $upsert_item);
salesforce_push_process_soap_results('Upsert', $results, $synced_entities);
}
if (!empty($upsert_list)) {
foreach ($upsert_list as $key => $upsert_item) {
$results = $soap->upsert($key, $upsert_item);
salesforce_push_process_soap_results('Upsert', $results, $synced_entities);
}
}
}
Expand Down Expand Up @@ -494,6 +518,7 @@ function salesforce_push_map_params($mapping, $entity_wrapper, &$key_field, &$ke
}

$fieldmap_type = salesforce_mapping_get_fieldmap_types($fieldmap['drupal_field']['fieldmap_type']);

$value = call_user_func($fieldmap_type['push_value_callback'], $fieldmap, $entity_wrapper);
$params[$fieldmap['salesforce_field']['name']] = $value;

Expand Down

0 comments on commit 4acc573

Please sign in to comment.