You are here

services_client.module in Services Client 7.2

Same filename and directory in other branches
  1. 7 services_client.module

File

services_client.module
View source
<?php

/**
 * @file
 *
 * Services client module allows to push different types of objects on
 * different types of events such as node_save, user_save to remote
 * masters.
 */
require_once dirname(__FILE__) . '/services_client.forms.inc';
require_once dirname(__FILE__) . '/services_client.plugins.inc';

/**
 * Implementation of hook_menu().
 */
function services_client_menu() {
  $items['admin/structure/services_client/list'] = array(
    'title' => 'List',
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['admin/structure/services_client/settings'] = array(
    'title' => 'Settings',
    'description' => 'Configure general client settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'services_client_settings',
    ),
    'access arguments' => array(
      'administer services client',
    ),
    'file' => 'services_client.admin.inc',
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/structure/services_client/wizard'] = array(
    'title' => 'Wizard',
    'description' => 'Import wizard to map fields from remote entity',
    'page callback' => 'services_client_wizard',
    'access arguments' => array(
      'administer services client',
    ),
    'file' => 'services_client.admin.inc',
    'type' => MENU_LOCAL_ACTION,
  );
  return $items;
}

/**
 * Implements hook_menu_alter().
 */
function services_client_menu_alter(&$items) {

  // Services client depends on services_client_connection while
  // services_client_connection can be used stand-alone. If we have the
  // combination, the following change makes it easier to navigate in the menu
  // between both.
  $items['admin/structure/services_client/connection']['type'] = MENU_LOCAL_TASK;
}

/**
 * Implementation of hook_cron_queue_info().
 */
function services_client_cron_queue_info() {
  if (variable_get('services_client_use_queue', FALSE) && variable_get('services_client_process_queue_cron', FALSE)) {
    $queues['services_client_sync'] = array(
      'worker callback' => 'services_client_queue_sync',
      'time' => 120,
    );
    return $queues;
  }
  else {
    return array();
  }
}

/**
 * Implements hook_theme().
 */
function services_client_theme() {
  return array(
    'services_client_mapping_rows' => array(
      'render element' => 'form',
      'file' => 'services_client.theme.inc',
    ),
  );
}

/**
 * Implementation of hook_permission
 *
 * @return array
 */
function services_client_permission() {
  return array(
    'administer services client' => array(
      'title' => t('Administer the services client'),
      'description' => t('Manage services client connections, hooks and mappings'),
      'restricted' => TRUE,
    ),
    'skip sending entity' => array(
      'title' => t('Allow user to skip sending entity saved via form'),
      'description' => t('Adds skip checkbox to each entity form'),
    ),
  );
}

/**
 * Get current site services client ID
 *
 * @return string
 *   ID of current site.
 */
function services_client_get_id() {
  return variable_get('services_client_id', drupal_get_token('services_client'));
}

/**
 * Retrieve object handler for given name.
 *
 * @param string $name
 *   Name of the event.
 *
 * @return EventHandler
 */
function services_client_get_event($name) {
  ctools_include('export');

  // Load event by name.
  $item = ctools_export_crud_load('services_client_connection_event', $name);
  if (!empty($item)) {
    return $item
      ->getHandler();
  }
  return NULL;
}

/**
 * Sync queued data to other sites. Drupal will use this function as callback
 * in cron run.
 *
 * @param array $data
 *   Data from queue that contain info about entity that needs to be synced.
 *   array(
 *     // Version to not process entities from old services_client v1 module.
 *     'version' => 2,
 *     // Entity that should be processed.
 *     'entity' => stdClass,
 *     // Name of event that should process entity.
 *     'name' => 'event_name',
 *   ),
 */
function services_client_queue_sync($data) {
  if (!empty($data['version']) && $data['version'] == 2) {
    $handler = services_client_get_event($data['event']);
    if ($handler) {
      $handler
        ->setEntity($data['entity']);
      if ($handler
        ->isMatching()) {
        return $handler
          ->execute();
      }
    }
  }
  else {
    $legacy_type_map = array(
      'node_save' => array(
        'node',
        'save',
      ),
      'node_delete' => array(
        'node',
        'delete',
      ),
      'user_save' => array(
        'user',
        'save',
      ),
    );
    $entity = $data['src_data'];
    $info = $legacy_type_map[$data['type']];
    $result = services_client_process_events($info[1], $entity, $info[0]);
    return reset($result);
  }
}

/**
 * Implements hook_form_alter().
 */
function services_client_form_alter(&$form, $form_state, $form_id) {
  if (services_client_is_entity_form($form, $form_state) && user_access('skip sending entity')) {
    $form['_services_client_exclude'] = array(
      '#type' => 'checkbox',
      '#title' => t('Skip services client syncing'),
      '#description' => t("Don't push this update via services client."),
    );
  }
  if ($form_id == 'ctools_export_ui_edit_item_form') {
    if ($form_state['plugin']['schema'] == 'services_client_connection') {
      $form['services_client_id'] = array(
        '#type' => 'textfield',
        '#title' => t('Remote client ID'),
        '#default_value' => isset($form_state['item']->services_client_id) ? $form_state['item']->services_client_id : NULL,
        '#description' => t('Enter ID of services client on remote endpoint.'),
        '#size' => 50,
      );
      $form['#submit'][] = 'services_client_form_submit_connection';
    }
  }
}

/**
 * Detect if form is entity form.
 *
 * @return bool
 *   TRUE if form is for entity.
 */
function services_client_is_entity_form($form, $form_state) {

  // Field attach API is adding these properties to each form with fields.
  if (!empty($form['#entity_type']) && !empty($form['#bundle'])) {
    return TRUE;
  }

  // Custom entities built via entity api module
  if (!empty($form_state['wrapper_callback']) && $form_state['wrapper_callback'] == 'entity_ui_main_form_defaults' && !empty($form_state['entity_type'])) {
    return TRUE;
  }
  return FALSE;
}

/**
 * Implements hook_entity_insert().
 */
function services_client_entity_insert($entity, $type) {
  if (module_exists('reference_uuid')) {
    reference_uuid_entity_load(array(
      $entity,
    ), $type);
  }
  services_client_process_events('save', $entity, $type);
}

/**
 * Implements hook_entity_update().
 */
function services_client_entity_update($entity, $type) {
  if (module_exists('reference_uuid')) {
    reference_uuid_entity_load(array(
      $entity,
    ), $type);
  }
  services_client_process_events('save', $entity, $type);
}

/**
 * Implements hook_entity_delete().
 */
function services_client_entity_delete($entity, $type) {
  if (module_exists('reference_uuid')) {
    reference_uuid_entity_load(array(
      $entity,
    ), $type);
  }
  services_client_process_events('delete', $entity, $type);
}

/**
 * Process entity by trigerring all events that are enabled and are matching
 * conditions.
 *
 * @param string $event
 *   Event type - 'save', 'delete'.
 *
 * @param stdClass $entity
 *   Drupal entity.
 *
 * @param string $entity_type
 *   Entity type name.
 *
 * @return array
 *   Array of ServicesClientEventResult objects which are representing
 *   all executed operations. This array doesn't include queued events.
 */
function services_client_process_events($event, $entity, $entity_type) {
  $events = services_client_event_load_active($event, $entity_type);
  $results = array();

  // Go through all events
  foreach ($events as $event) {
    $handler = $event
      ->getHandler();
    $handler
      ->setEntity($entity);

    // Entity can be synced to event in following cases
    // 1. Event is auto triggered
    // 2. Entity shouldn't be skipped
    // 3. Enttiy shouldn't be processed via queue
    if ($handler
      ->isAutoTriggered() && !$handler
      ->skipAutosync()) {

      // Check if entity matches all event sync conditions.
      if ($handler
        ->isMatching()) {

        // Check if shouldn't be enqueued.
        if (!$handler
          ->enqueue()) {
          $results[] = $handler
            ->execute();
        }
      }
    }
  }

  // Allow other modules to react on changes.
  if (!empty($results)) {
    module_invoke_all('services_client_process_events', $results);
  }
  return $results;
}

/**
 * Load all active services client events.
 *
 * @param string $event
 *   Event type - 'save', 'delete'.
 *
 * @param string $entity_type
 *   Entity type name.
 *
 * @return array
 *   Loaded events matching condition and active.
 */
function services_client_event_load_active($event, $entity_type) {

  // Load events with ctools export, filter disbled.
  ctools_include('export');
  $events = array_filter(ctools_export_crud_load_all('services_client_connection_event'), function ($item) use ($event, $entity_type) {
    return empty($item->disabled) && $item->event == $event && $item->entity_type == $entity_type;
  });
  return $events;
}

/**
 * Add customer services_client_id to connection
 */
function services_client_form_submit_connection($form, &$form_state) {
  if (isset($form_state['values']['services_client_id']) && !empty($form_state['values']['services_client_id'])) {
    $form_state['item']->services_client_id = $form_state['values']['services_client_id'];
  }
}

/**
 * Implements hook_services_client_connection_save().
 */
function services_client_services_client_connection_save($connection) {
  if (!empty($connection->services_client_id)) {
    db_merge('services_client_connection_id')
      ->key(array(
      'name' => $connection->name,
    ))
      ->fields(array(
      'services_client_id' => $connection->services_client_id,
    ))
      ->execute();
  }
}

/**
 * Implements hook_services_client_connection_load().
 */
function services_client_services_client_connection_load($connection) {
  if ($id = services_client_get_connection_id($connection->name)) {
    $connection->services_client_id = $id;
  }
}

/**
 * Load remote services client id for connection
 */
function services_client_get_connection_id($name) {
  $cache =& drupal_static(__FUNCTION__);
  if (!isset($cache[$name])) {
    $sql = "SELECT services_client_id FROM {services_client_connection_id} WHERE name = :name";
    $cache[$name] = db_query($sql, array(
      ':name' => $name,
    ))
      ->fetchField();
  }
  return isset($cache[$name]) ? $cache[$name] : NULL;
}

/**
 * Implements hook_services_client_skip_autosync().
 */
function services_client_services_client_skip_autosync($handler, $entity, $entity_type) {

  // This would prevent syncing uid 1 account by default.
  $uids = explode(',', trim(variable_get('services_client_exclude_users', '1')));
  if ($entity_type == 'user' && in_array($entity->uid, $uids)) {
    watchdog('services_client', 'USER EXCLUDE: uid : @uid, event : @event', array(
      '@uid' => $entity->uid,
      '@event' => $handler
        ->getEvent()->name,
    ), WATCHDOG_NOTICE);
    return TRUE;
  }
}

Functions

Namesort descending Description
services_client_cron_queue_info Implementation of hook_cron_queue_info().
services_client_entity_delete Implements hook_entity_delete().
services_client_entity_insert Implements hook_entity_insert().
services_client_entity_update Implements hook_entity_update().
services_client_event_load_active Load all active services client events.
services_client_form_alter Implements hook_form_alter().
services_client_form_submit_connection Add customer services_client_id to connection
services_client_get_connection_id Load remote services client id for connection
services_client_get_event Retrieve object handler for given name.
services_client_get_id Get current site services client ID
services_client_is_entity_form Detect if form is entity form.
services_client_menu Implementation of hook_menu().
services_client_menu_alter Implements hook_menu_alter().
services_client_permission Implementation of hook_permission
services_client_process_events Process entity by trigerring all events that are enabled and are matching conditions.
services_client_queue_sync Sync queued data to other sites. Drupal will use this function as callback in cron run.
services_client_services_client_connection_load Implements hook_services_client_connection_load().
services_client_services_client_connection_save Implements hook_services_client_connection_save().
services_client_services_client_skip_autosync Implements hook_services_client_skip_autosync().
services_client_theme Implements hook_theme().