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.moduleView 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;
}