You are here

sf_node.module in Salesforce Suite 5.2

Same filename and directory in other branches
  1. 6.2 sf_node/sf_node.module

Integrates the core node object and various node related modules with the SalesForce API.

File

sf_node/sf_node.module
View source
<?php

/**
 * @file
 * Integrates the core node object and various node related modules with the
 *   SalesForce API.
 */

/**
 * Implementation of hook_menu().
 */
function sf_node_menu($may_cache) {
  $items = array();
  if (arg(0) == 'node' && is_numeric(arg(1)) && user_access('sync nodes with salesforce')) {
    $items[] = array(
      'path' => 'node/' . arg(1) . '/salesforce',
      'title' => t('Salesforce'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'sf_node_salesforce_form',
        arg(1),
      ),
      'access' => user_access('sync nodes with salesforce'),
      'type' => MENU_LOCAL_TASK,
    );
  }
  return $items;
}

/**
 * Implementation of hook_perm().
 */
function sf_node_perm() {
  return array(
    'sync nodes with salesforce',
  );
}

/**
 * Implementation of hook_form_alter().
 */
function sf_node_form_alter($form_id, &$form) {
  if ($form_id == 'salesforce_api_settings_form') {
    $form['sf_node'] = array(
      '#type' => 'fieldset',
      '#title' => t('Node integration'),
      '#description' => t('Placeholder for any node integration settings.'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
    );
  }
}

/**
 * Implementation of hook_nodeapi().
 */
function sf_node_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  switch ($op) {
    case 'load':
      $node->salesforce = salesforce_api_id_load('node', $node->nid);
      break;
  }
}

/**
 * Implementation of hook_fieldmap_objects_alter().
 */
function sf_node_fieldmap_objects($type) {
  $objects = array();

  // Define the data fields available for Drupal objects.
  if ($type == 'drupal') {

    // Add a definition for each node type.
    foreach (node_get_types() as $type) {

      // Define the node type object with the node ID field.
      $objects['node_' . $type->type] = array(
        'label' => t('@name node', array(
          '@name' => $type->name,
        )),
        'fields' => array(
          'nid' => array(
            'label' => t('Node ID'),
            'type' => SALESFORCE_FIELD_SOURCE_ONLY,
          ),
        ),
      );

      // Add a title field if the node type has one.
      if ($type->has_title) {
        $objects['node_' . $type->type]['fields']['title'] = array(
          'label' => check_plain($type->title_label),
          'type' => SALESFORCE_FIELD_REQUIRED,
        );
      }

      // Add a body field if the node type has one.
      if ($type->has_body) {
        $objects['node_' . $type->type]['fields']['body'] = array(
          'label' => check_plain($type->body_label),
        );
      }

      // Add the rest of the core fields.
      $objects['node_' . $type->type]['fields'] += array(
        'type' => array(
          'label' => t('Node type'),
        ),
        'status' => array(
          'label' => t('Is the node published?'),
        ),
        'promote' => array(
          'label' => t('Is the node promoted?'),
        ),
        'created' => array(
          'label' => t('Created timestamp'),
        ),
        'uid' => array(
          'label' => t("Author's user ID"),
        ),
        'name' => array(
          'label' => t("Author's name"),
        ),
      );
    }

    // Add CCK fields to the node object definitions.
    if (module_exists('content')) {

      // Loop through each of the content types.
      foreach (content_types() as $type) {

        // Add each of the fields to the node object definition.
        foreach ((array) $type['fields'] as $field) {

          // Choose a handler based on the type of the CCK field.
          switch ($field['type']) {

            // TODO: Decide if we want to make more specific handlers...
            // case 'text':
            // For example, I might set a handler for text fields that takes
            // the selected input format into account.
            default:
              $export_handler = '_sf_node_export_cck_default';
              $import_handler = '_sf_node_import_cck_default';
          }
          $objects['node_' . $type['type']]['fields'][$field['field_name']] = array(
            'label' => check_plain($field['widget']['label']),
            'group' => t('CCK fields'),
            'export' => $export_handler,
            'import' => $import_handler,
          );

          // If the field was a date field, add the "To" date if enabled.
          if ($field['type'] == 'date' && !empty($field['todate'])) {
            $objects['node_' . $type['type']]['fields'][$field['field_name'] . '_todate'] = array(
              'label' => t('@label (to date)', array(
                '@label' => $field['widget']['label'],
              )),
              'group' => t('CCK fields'),
              'export' => '_sf_node_export_cck_todate',
              'import' => '_sf_node_import_cck_todate',
            );
          }
        }
      }
    }
  }
  return $objects;
}

// Returns the basic value of a CCK field from $array[0]['value'].
function _sf_node_export_cck_default($source, $field) {

  // Get the data array for the field.
  $data = $source->{$field};

  // Return the first value; currently doesn't support multiple value fields.
  return $data[0]['value'];
}

// Returns the basic value of a CCK field from $array[0]['value'].
function _sf_node_import_cck_default(&$node, $key, $source, $field) {
  $data = $node->{$key};
  $data[0]['value'] = $source->{$field};
  $node->{$key} = $data;
}

// Returns the todate for a CCK date field.
function _sf_node_export_cck_todate($source, $field) {

  // Get the name of the actual CCK field.
  $key = substr($field, 0, strlen($field) - 7);

  // Get the data array for the field.
  $data = $source->{$key};

  // Return the to date from the field data.
  return $data[0]['value2'];
}

// Returns the todate for a CCK date field.
function _sf_node_import_cck_todate(&$node, $key, $source, $field) {
  $key = substr($key, 0, strlen($key) - 7);
  $data = $node->{$key};
  $data[0]['value2'] = $source->{$field};
  $node->{$key} = $data;
}

// Displays the Salesforce synchronization form.
function sf_node_salesforce_form($nid) {
  $node = node_load($nid);

  // Fail out if the node didn't exist!
  if (!$node->nid) {
    drupal_not_found();
  }

  // Set the node page title.
  drupal_set_title(check_plain($node->title));
  $form = array();
  $form['nid'] = array(
    '#type' => 'value',
    '#value' => $nid,
  );

  // Display an export button if the node hasn't been exported before.
  if (!$node->salesforce['sfid']) {
    $form['export'] = array(
      '#type' => 'fieldset',
      '#title' => t('Export node to Salesforce'),
      '#description' => t('This node may be exported to Salesforce using any fieldmap listed below.'),
    );

    // Get an array of fieldmaps that export nodes of this type to Salesforce.
    $options = salesforce_api_fieldmap_options('export', 'node_' . $node->type);

    // If no corresponding fieldmaps were found...
    if (count($options) == 0) {

      // Display a message appropriate to the user's permissions.
      if (user_access('administer salesforce')) {
        $form['export']['#description'] = t('To export this node you must first <a href="!url">add a fieldmap</a> that exports @type nodes.', array(
          '!url' => url(SALESFORCE_PATH_FIELDMAPS . '/add'),
          '@type' => $node->type,
        ));
      }
      else {
        $form['export']['#description'] = t('Please contact a site administrator to add a fieldmap that exports @type nodes.', array(
          '@type' => $node->type,
        ));
      }
    }
    else {

      // Otherwise add the export form!
      $form['export']['fieldmap'] = array(
        '#type' => 'select',
        '#title' => t('Export fieldmap'),
        '#options' => $options,
      );
      $form['export']['export_node'] = array(
        '#type' => 'submit',
        '#value' => t('Export node'),
      );
    }
  }
  else {

    // Otherwise add synchronization information.
    $form['sfid'] = array(
      '#type' => 'value',
      '#value' => $node->salesforce['sfid'],
    );
    $form['fieldmap'] = array(
      '#type' => 'value',
      '#value' => $node->salesforce['fieldmap'],
    );

    // Retrieve the object from Salesforce.
    $sf = salesforce_api_connect();
    $data = $sf
      ->retrieve(array(
      $node->salesforce['sfid'],
    ), $node->salesforce['fieldmap']);

    // Load the fieldmap data.
    $map = salesforce_api_fieldmap_load($node->salesforce['fieldmap']);

    // Load the object definitions.
    $drupal_object = salesforce_api_fieldmap_objects_load('drupal', $map['drupal']);
    $object = salesforce_api_fieldmap_objects_load('salesforce', $map['salesforce']);
    $header = array(
      t('Field name'),
      t('Drupal @type value', array(
        '@type' => salesforce_api_fieldmap_object_label('drupal', $map['drupal']),
      )),
      t('Salesforce @type value', array(
        '@type' => salesforce_api_fieldmap_object_label('salesforce', $map['salesforce']),
      )),
    );
    $rows = array();
    foreach ($map['fields'] as $key => $value) {
      if (isset($drupal_object['fields'][$value]['export'])) {
        $drupal_value = $drupal_object['fields'][$value]['export']($node, $value);
      }
      elseif (isset($node->{$value})) {
        $drupal_value = $node->{$value};
      }
      else {
        $drupal_value = '';
      }
      $rows[] = array(
        $object['fields'][$key]['label'],
        $drupal_value,
        $data->{$key},
      );
    }
    $form['mapped'] = array(
      '#type' => 'fieldset',
      '#title' => t('Mapped field values'),
      '#description' => t('These fields have been mapped through <a href="!url">fieldmap @index</a>.', array(
        '!url' => url(SALESFORCE_PATH_FIELDMAPS . '/' . $node->salesforce['fieldmap'] . '/edit'),
        '@index' => $node->salesforce['fieldmap'],
      )),
    );
    $form['mapped']['fieldmap_values'] = array(
      '#value' => theme('table', $header, $rows),
    );
    $form['mapped']['export_values'] = array(
      '#type' => 'submit',
      '#value' => t('Export changes to Salesforce'),
      '#attributes' => array(
        'class' => 'sf-confirm',
      ),
    );
    $form['mapped']['import_values'] = array(
      '#type' => 'submit',
      '#value' => t('Import changes from Salesforce'),
      '#attributes' => array(
        'class' => 'sf-confirm',
      ),
    );

    // Create a table for the unmapped fields.
    $header = array(
      t('Field name'),
      t('Salesforce @type value', array(
        '@type' => salesforce_api_fieldmap_object_label('salesforce', $map['salesforce']),
      )),
    );
    $rows = array();
    foreach ((array) $data as $key => $value) {
      if (!isset($map['fields'][$key]) && isset($object['fields'][$key])) {
        $rows[] = array(
          $object['fields'][$key]['label'],
          $value,
        );
      }
    }
    if (count($rows) > 0) {
      $form['unmapped'] = array(
        '#type' => 'fieldset',
        '#title' => t('Unmapped fields'),
        '#description' => t('These fields are available on SalesForce but are not currently mapped through the fieldmap used for this user.'),
      );
      $form['unmapped']['unmmaped_fields'] = array(
        '#value' => theme('table', $header, $rows),
      );
    }
    $rows = array();
    foreach (salesforce_api_fieldmap_system_fields() as $key => $value) {
      $rows[] = array(
        $value['label'],
        $data->{$key},
      );
    }
    $form['system'] = array(
      '#type' => 'fieldset',
      '#title' => t('System fields'),
      '#description' => t('These fields provide additional system information about the Salesforce object but cannot be exported to Salesforce.'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
    );
    $form['system']['system_fields'] = array(
      '#value' => theme('table', $header, $rows),
    );
    $form['raw'] = array(
      '#type' => 'fieldset',
      '#title' => t('Raw data'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
    );
    $form['raw']['data'] = array(
      '#value' => '<pre>' . print_r($data, TRUE) . '</pre>',
    );
  }
  return $form;
}
function sf_node_salesforce_form_submit($form_id, $form_values) {
  switch ($form_values['op']) {

    // Export the node to Salesforce.
    case t('Export node'):
      if (sf_node_export($form_values['nid'], $form_values['fieldmap'])) {
        drupal_set_message(t('Node successfully exported to Salesforce.'));
      }
      else {
        drupal_set_message(t('An error occurred while exporting the node to Salesforce.  Check the watchdog for more information.'), 'error');
      }
      break;

    // Export changes to Salesforce.
    case t('Export changes to Salesforce'):
      if (sf_node_export($form_values['nid'], $form_values['fieldmap'], $form_values['sfid'])) {
        drupal_set_message(t('Changes successfully exported to Salesforce.'));
      }
      else {
        drupal_set_message(t('An error occurred while exporting the changes to Salesforce.  Check the watchdog for more information.'), 'error');
      }
      break;

    // Import changes from Salesforce.
    case t('Import changes from Salesforce'):
      if (sf_node_import($form_values['sfid'], $form_values['fieldmap'], $form_values['nid'])) {
        drupal_set_message(t('The node has been updated with values from Salesforce.'));
      }
      else {
        drupal_set_message(t('An error occurred while importing the changes from Salesforce.  Check the watchdog for more information.'), 'error');
      }
      break;
  }
}

/**
 * Exports a node to Salesforce using the specified fieldmap and stores the
 *   ID of the Salesforce object for the node.
 *
 * @param $nid
 *   The nid of the node to export.
 * @param $fieldmap
 *   The index of the fieldmap to use to create the export object.
 * @param $sfid
 *   The Salesforce ID of the object you want to update.  If left NULL, a new
 *     object will be created at Salesforce.
 * @return
 *   TRUE or FALSE indicating the success of the operation.
 */
function sf_node_export($nid, $fieldmap, $sfid = NULL) {

  // Attempt to connect to Salesforce.
  $sf = salesforce_api_connect();

  // Load the node.
  $node = node_load($nid);

  // Create an object for export based on the specified fieldmap.
  $object = salesforce_api_fieldmap_export_create($fieldmap, $node);

  // Load the fieldmap so we can get the object name.
  $map = salesforce_api_fieldmap_load($fieldmap);
  if (empty($sfid)) {

    // Export the object to Salesforce.
    $response = $sf->client
      ->create(array(
      $object,
    ), $map['salesforce']);
  }
  else {
    $object->Id = $sfid;
    $response = $sf->client
      ->update(array(
      $object,
    ), $map['salesforce']);
  }

  // If the export was successful...
  if ($response->success) {
    if (empty($sfid)) {

      // Store the Salesforce ID for the node and return TRUE.
      salesforce_api_id_save('node', $nid, $response->id, $fieldmap);
    }
    return TRUE;
  }
  else {

    // Otherwise log the error and return FALSE.
    drupal_set_message('<pre>' . print_r($response, TRUE) . '</pre>', 'error');
    return FALSE;
  }
}

/**
 * Imports data from Salesforce into a node.
 *
 * @param $sfid
 *   The Salesforce ID of the object from which you want to import.
 * @param $fieldmap
 *   The index of the fieldmap to use to create the export object.
 * @param $nid
 *   The nid of the node to update.  If left NULL, a new node will be created.
 * @return
 *   The nid of the imported node or FALSE on failure.
 */
function sf_node_import($sfid, $fieldmap, $nid = NULL) {

  // Retrieve the object from Salesforce.
  $sf = salesforce_api_connect();
  $data = $sf
    ->retrieve(array(
    $sfid,
  ), $fieldmap);

  // Return FALSE if the object data was not found at Salesforce.
  if (empty($data)) {
    return FALSE;
  }

  // Load the fieldmap data.
  $map = salesforce_api_fieldmap_load($fieldmap);

  // Load the object definitions.
  $drupal_object = salesforce_api_fieldmap_objects_load('drupal', $map['drupal']);
  $salesforce_object = salesforce_api_fieldmap_objects_load('salesforce', $map['salesforce']);

  // If a node was specified, attempt to load it.
  $node = node_load($nid);

  // If the node exists, simply update the existing node.
  if ($node->nid) {

    // Loop through the fields on the fieldmap.
    foreach ($map['fields'] as $value => $key) {

      // If a handler is specified for importing a value from Salesforce.
      if (isset($drupal_object['fields'][$key]['import'])) {

        // Get the value for the field from the handler function.
        $drupal_object['fields'][$key]['import']($node, $key, $data, $value);
      }
      elseif (isset($data->{$value})) {

        // Otherwise set the field on the export object to the value of the source
        // field if it's present on the source object.
        $node->{$key} = $data->{$value};
      }
    }
    node_save($node);
  }
  return $node->nid;
}

Functions

Namesort descending Description
sf_node_export Exports a node to Salesforce using the specified fieldmap and stores the ID of the Salesforce object for the node.
sf_node_fieldmap_objects Implementation of hook_fieldmap_objects_alter().
sf_node_form_alter Implementation of hook_form_alter().
sf_node_import Imports data from Salesforce into a node.
sf_node_menu Implementation of hook_menu().
sf_node_nodeapi Implementation of hook_nodeapi().
sf_node_perm Implementation of hook_perm().
sf_node_salesforce_form
sf_node_salesforce_form_submit
_sf_node_export_cck_default
_sf_node_export_cck_todate
_sf_node_import_cck_default
_sf_node_import_cck_todate