You are here

pmpapi_pull.module in Public Media Platform API Integration 7

Allows admins to pull content from the PMP API, and turn PMP docs into (locally-stored, independent) drupal entities.

File

pmpapi_pull/pmpapi_pull.module
View source
<?php

/**
* @file
* Allows admins to pull content from the PMP API, and turn PMP docs into
  (locally-stored, independent) drupal entities.
*/

/**
 * Implements hook_permission().
 */
function pmpapi_pull_permission() {
  return array(
    'administer PMP pull' => array(
      'title' => t('Administer pulls from the PMP API'),
      'description' => t('Perform administration tasks for pulls from the PMP API.'),
    ),
    'pull PMP content' => array(
      'title' => t('Pull PMP content'),
      'description' => t('Pull PMP content to create entities.'),
    ),
  );
}

/**
 * Implements hook_menu().
 */
function pmpapi_pull_menu() {
  $items = array();
  $items['admin/content/pmp/pull'] = array(
    'title' => 'Pull PMP Doc',
    'description' => 'Pull a single doc from the PMP API.',
    'access arguments' => array(
      'pull PMP content',
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'pmpapi_pull_pull_doc_by_guid',
    ),
    'file' => 'pmpapi_pull.pages.inc',
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/config/services/pmp/pull'] = array(
    'title' => 'Pull settings',
    'description' => 'Select which content types (and mapped fields) to pull from PMP.',
    'access arguments' => array(
      'administer PMP pull',
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'pmpapi_pull_admin_config',
    ),
    'file' => 'pmpapi_pull.admin.inc',
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/content/pmp/search'] = array(
    'title' => 'Search PMP docs',
    'description' => 'Search PMP docs',
    'access arguments' => array(
      'pull PMP content',
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'pmpapi_pull_filter_form',
    ),
    'type' => MENU_LOCAL_TASK,
    'file' => 'pmpapi_pull.pages.inc',
  );
  $items['admin/content/pmp/search/%'] = array(
    'title' => 'Search PMP docs',
    'description' => 'Search PMP docs',
    'access arguments' => array(
      'pull PMP content',
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'pmpapi_pull_filter_form',
      4,
    ),
    'file' => 'pmpapi_pull.pages.inc',
  );
  $items['admin/content/pmp/preview/%'] = array(
    'title' => 'Preview PMP Document',
    'access arguments' => array(
      'pull PMP content',
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'pmpapi_pull_preview',
      4,
    ),
    'file' => 'pmpapi_pull.pages.inc',
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implements hook_cron().
 */
function pmpapi_pull_cron() {
  pmpapi_pull_check_valid_dates();
}

/**
 * Determines if the validity of a pulled doc has changed, and changes the
 * corresponding node accordingly.
 */
function pmpapi_pull_check_valid_dates() {
  $docs = db_query('SELECT * FROM {pmpapi_pull_pulled_docs}');
  $timestamp = time();

  // more expensive, but more accurate than REQUEST_TIME
  foreach ($docs as $doc) {
    $now = pmpapi_convert_timestamp($timestamp);
    $guid = $doc->guid;
    $from = pmpapi_convert_timestamp(strtotime($doc->valid_from));
    $to = pmpapi_convert_timestamp(strtotime($doc->valid_to));
    $last_check_timestamp = variable_get('pmpapi_pull_last_validity_check');
    $last_check = pmpapi_convert_timestamp($last_check_timestamp);
    if ($now >= $from && $now <= $to && $last_check <= $from) {
      $entity = pmpapi_get_entity_from_guid($guid);
      $type = pmpapi_get_entity_type_from_guid($guid);
      if ($entity && $type != 'file' && empty($entity->status)) {
        $entity->status = 1;
        entity_save($type, $entity);
      }
    }
    elseif ($now > $to && $last_check <= $to) {
      $entity = pmpapi_get_entity_from_guid($guid);
      $type = pmpapi_get_entity_type_from_guid($guid);
      if ($entity && $type != 'file' && !empty($entity->status)) {
        $entity->status = 0;
        entity_save($type, $entity);
      }
    }
  }
  variable_set('pmpapi_pull_last_validity_check', $timestamp);
}

/**
 * Finds the mapped entity for a given PMP profile.
 *
 * @param $profile string
 *   The name of a PMP profile
 *
 * @return array
 *   The entity type and bundle name of the mapped entity
 */
function pmpapi_pull_find_mapped_entity($profile) {
  foreach (entity_get_info() as $entity_type => $entity) {
    $bundles = $entity['bundles'];
    foreach ($bundles as $bundle_name => $bundle) {
      $uname = $entity_type . '__' . $bundle_name;
      $mapped_profile = variable_get('pmpapi_pull_' . $uname . '_profile');
      if ($mapped_profile == $profile) {
        return array(
          'entity_type' => $entity_type,
          'bundle_name' => $bundle_name,
        );
      }
    }
  }
}

/**
 * Pulls a single PMP doc.
 *
 * @param $guid string
 *   The GUID of the doc to be pulled.
 *
 * @param $cache boolean
 *   Whether or not pull should first check cache.
 *
 */
function pmpapi_pull_pull_doc($guid, $cache = FALSE) {
  if (variable_get('pmpapi_pull_pull_active')) {
    $pmp = new PMPAPIDrupalPull($cache);
    $entity = $pmp
      ->pullDoc($guid);
    if ($entity) {
      return $entity;
    }
    else {
      drupal_set_message(t('No doc could be found in the PMP with this guid.'), 'warning');
    }
  }
  else {
    drupal_set_message(t('Unable to pull doc with guid = @guid. Pull is not currently active.', array(
      '@guid' => $guid,
    )), 'warning');
  }
}

/**
 * Determines if an entity with a certain GUID already exists.
 *
 * @param string $guid
 *   The GUID in question
 *
 * @return boolean
 *  TRUE if doc already exists locally, FALSE otherwise.
 */
function pmpapi_pull_doc_exists($guid) {
  return pmpapi_pull_get_nid_from_guid($guid);
}

/**
 * Determines if a doc has already been pulled from the PMP API (and saved as an
 * entity locally).
 *
 * @param string $guid
 *   The GUID of the doc
 *
 * @return boolean
 *  TRUE if doc already exists locally, FALSE otherwise.
 */
function pmpapi_pull_doc_has_been_pulled($guid) {
  return db_query('SELECT guid FROM {pmpapi_pull_pulled_docs} WHERE guid=:guid', array(
    ':guid' => $guid,
  ))
    ->fetchField();
}

/**
 * Implements hook_entity_insert().
 */
function pmpapi_pull_entity_insert($entity, $type) {
  if (!empty($entity->pmpapi_guid) && !empty($entity->pmpapi_pull)) {
    db_merge('pmpapi_pull_pulled_docs')
      ->key(array(
      'guid' => $entity->pmpapi_guid,
    ))
      ->fields(array(
      'guid' => $entity->pmpapi_guid,
      'changed' => REQUEST_TIME,
      'valid_from' => $entity->pmpapi_valid_from,
      'valid_to' => $entity->pmpapi_valid_to,
    ))
      ->execute();
  }
}

/**
 * Implements hook_entity_update().
 */
function pmpapi_pull_entity_update($entity, $type) {
  if (!empty($entity->pmpapi_guid) && pmpapi_pull_doc_has_been_pulled($entity->pmpapi_guid)) {
    $update = db_update('pmpapi_pull_pulled_docs')
      ->condition('guid', $entity->pmpapi_guid);
    $fields = array(
      'changed' => REQUEST_TIME,
    );

    // Only update valid_from and valid_to if fields are defined on the entity
    if (!empty($entity->pmpapi_valid_from)) {
      $fields['valid_from'] = $entity->pmpapi_valid_from;
    }
    if (!empty($entity->pmpapi_valid_to)) {
      $fields['valid_to'] = $entity->pmpapi_valid_to;
    }
    $update
      ->fields($fields);
    $update
      ->execute();

    // Other modules might try to remove the doc from API on update (e.g., if
    // status set to 0). This property will prevent that.
    $entity->pmpapi_do_not_remove = TRUE;
  }
}

/**
 * Implements hook_entity_delete().
 */
function pmpapi_pull_entity_delete($entity, $type) {
  if (!empty($entity->pmpapi_guid) && pmpapi_pull_doc_has_been_pulled($entity->pmpapi_guid)) {
    db_delete('pmpapi_pull_pulled_docs')
      ->condition('guid', $entity->pmpapi_guid)
      ->execute();

    // Entity is gone, but other hooks still might try to remove this doc from
    // the PMP API. This property will prevent that.
    $entity->pmpapi_do_not_remove = TRUE;
  }
}

/**
 * Gets all entity info.
 *
 * Basically a wrapper around entity_get_info(), in case modules want to alter the
 * returned entity info.
 *
 * @return array
 *   (Possibly altered) info on all defined entities.
 */
function pmpapi_pull_get_entities() {
  $entities = entity_get_info();
  drupal_alter('pmpapi_pull_get_entities', $entities);
  return $entities;
}

/**
 * Implements hook_pmpapi_push_entity_ok_to_push().
 */
function pmpapi_pull_pmpapi_push_entity_ok_to_push($entity, $type) {

  // Pull flag means never push
  if (!empty($entity->pmpapi_pull)) {
    return FALSE;
  }

  // If no guid, not enough info to invalidate push
  if (empty($entity->pmpapi_guid)) {
    return TRUE;
  }

  // If doc has not been previously pulled, entity is OK
  if (!pmpapi_pull_doc_has_been_pulled($entity->pmpapi_guid)) {
    return TRUE;
  }

  // Make sure we explicitly return FALSE
  return FALSE;
}

/**
 * Finds file extension of a given mimetype.
 *
 * @param $mimetype string
 *   A valid mimetype
 *
 * @return string
 *   A file extension
 */
function pmpapi_pull_get_ext_from_mimetype($mimetype) {

  // Convert mimetype string (e.g., 'image/jpeg') into file extension (e.g., 'jpg')
  require_once DRUPAL_ROOT . '/' . 'includes/file.mimetypes.inc';
  $mappings = file_mimetype_mapping();

  // Create an array that maps mimetype string to integer (mimetype constant)
  $mimetypes = array_flip($mappings['mimetypes']);

  // Create an array that maps integer (mimetype constant) into file extension
  $extensions = array_flip($mappings['extensions']);

  // Convert mimetype string into extension
  $ext = $extensions[$mimetypes[$mimetype]];
  return $ext;
}

/**
 * Implements hook_pmpapi_profile_info_alter().
 */
function pmpapi_pull_pmpapi_profile_info_alter(&$info) {
  $profile_info = module_invoke_all('pmpapi_profile_info');
  $profiles = array_keys($profile_info);
  $items = array();
  foreach ($profiles as $profile) {
    $items['item-' . $profile] = array(
      'type' => 'item',
      'accepted_types' => array(
        'image',
        'file',
        'entityreference',
      ),
      'multiple' => TRUE,
    );
  }
  foreach ($info as $profile_name => $profile) {
    if (!empty($profile['item'])) {
      unset($info[$profile_name]['item']);
    }
    foreach ($items as $item_name => $item) {
      $info[$profile_name][$item_name] = $item;
    }
  }
}

/**
 * Implements hook_pmpapi_pull_make_local_files().
 */
function pmpapi_pull_make_local_files($profile) {
  $make_local_files = module_invoke_all('pmpapi_pull_make_local_files', $profile);
  return !in_array(FALSE, $make_local_files, TRUE);
}

/**
 * Determines the URL of a given PMP enclosure object.
 *
 * This functions solely exists to deal with the way APM points to audio files in
 * the PMP.
 *
 * @param object $enclosure
 *   A PMP enclosure object
 *
 * @return string
 *   The URI of the enclosure file
 */
function pmpapi_pull_get_enclosure_url($enclosure) {
  if (pmpapi_url_is_m3u($enclosure->href)) {

    // NPR enclosures are M3Us; we need to crack that file and extract the MP3
    $uri = pmpapi_get_mp3_from_m3u($enclosure->href);
  }
  elseif (stripos($enclosure->href, 'apm-audio:') !== 0) {
    $uri = $enclosure->href;
  }
  else {
    $file = $enclosure->meta->api->href;
    $call = drupal_http_request($file, array(
      'timeout' => 3,
    ));
    if ($call->code == '200') {
      $json = json_decode($call->data);
      if (!empty($json->{$enclosure->href}->podcast->http_file_path)) {
        $uri = $json->{$enclosure->href}->podcast->http_file_path;
      }
      else {
        drupal_set_message(t('Unable to extract an http_file_path for the file:') . ' ' . check_url($enclosure->href), 'warning');
      }
    }
    else {
      drupal_set_message(t('Unable to extract a URL for the file:') . ' ' . check_url($enclosure->href), 'warning');
    }
  }
  return $uri;
}

Functions

Namesort descending Description
pmpapi_pull_check_valid_dates Determines if the validity of a pulled doc has changed, and changes the corresponding node accordingly.
pmpapi_pull_cron Implements hook_cron().
pmpapi_pull_doc_exists Determines if an entity with a certain GUID already exists.
pmpapi_pull_doc_has_been_pulled Determines if a doc has already been pulled from the PMP API (and saved as an entity locally).
pmpapi_pull_entity_delete Implements hook_entity_delete().
pmpapi_pull_entity_insert Implements hook_entity_insert().
pmpapi_pull_entity_update Implements hook_entity_update().
pmpapi_pull_find_mapped_entity Finds the mapped entity for a given PMP profile.
pmpapi_pull_get_enclosure_url Determines the URL of a given PMP enclosure object.
pmpapi_pull_get_entities Gets all entity info.
pmpapi_pull_get_ext_from_mimetype Finds file extension of a given mimetype.
pmpapi_pull_make_local_files Implements hook_pmpapi_pull_make_local_files().
pmpapi_pull_menu Implements hook_menu().
pmpapi_pull_permission Implements hook_permission().
pmpapi_pull_pmpapi_profile_info_alter Implements hook_pmpapi_profile_info_alter().
pmpapi_pull_pmpapi_push_entity_ok_to_push Implements hook_pmpapi_push_entity_ok_to_push().
pmpapi_pull_pull_doc Pulls a single PMP doc.