pmpapi.module in Public Media Platform API Integration 7
Creates basic calls to the PMP API.
File
pmpapi.moduleView source
<?php
/**
* @file
* Creates basic calls to the PMP API.
*/
/**
* Implements hook_permisssion().
*/
function pmpapi_permission() {
return array(
'administer PMP API' => array(
'title' => t('Administer the PMP API'),
'description' => t('Perform administration tasks for the PMP API.'),
),
);
}
/**
* Implements hook_menu().
*/
function pmpapi_menu() {
$items['admin/config/services/pmp'] = array(
'title' => 'Public Media Platform (PMP) API',
'description' => 'Control your PMP API settings',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'pmpapi_config_form',
),
'access arguments' => array(
'administer PMP API',
),
'file' => 'pmpapi.admin.inc',
);
$items['admin/config/services/pmp/api_config'] = array(
'title' => 'API Settings',
'weight' => -20,
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['admin/config/services/pmp/api_test'] = array(
'title' => 'Test PMP API',
'page callback' => 'pmpapi_test_api',
'access arguments' => array(
'administer PMP API',
),
'file' => 'pmpapi.pages.inc',
);
return $items;
}
/**
* Fetches a single doc from the PMP.
*
* @param $guid
* A guid.
*
* @return object
* An PMPAPIDrupal object, or NULL if errors.
*/
function pmpapi_fetch($guid, $cache = TRUE) {
$pmp = new PMPAPIDrupal($cache);
if (empty($pmp->errors)) {
$pmp
->pull(array(
'guid' => $guid,
));
}
return $pmp;
}
/**
* Fetches multiple docs from the PMP, narrowed by query-type parameters.
*
* @param $params
* PMP query parameters.
*
* @return object
* An PMPAPIDrupal object, or NULL if errors.
*/
function pmpapi_query($params, $cache = TRUE) {
$pmp = new PMPAPIDrupal($cache);
if (empty($pmp->errors)) {
$pmp
->pull($params);
}
return $pmp;
}
/**
* Sends a doc to the PMP.
*
* @param $values
* Key/value pairs of data to be sent to the PMP.
*
* @return object
* An PMPAPIDrupal object.
*/
function pmpapi_send($values) {
$pmp = new PMPAPIDrupal();
$doc = $pmp
->createDoc($values);
return $pmp
->push($doc);
}
/**
* Generates a GUID (UUID v4).
*
* @return string
* A GUID (UUID v4).
*/
function pmpapi_guid() {
$pmp = new PMPAPIDrupal();
$guid = $pmp
->guid();
return $guid;
}
/**
* A very, very simple health check.
*
* @return boolean
* TRUE if there are no PMP errors, FALSE otherwise.
*/
function pmpapi_ping() {
$pmp = new PMPAPIDrupal(FALSE);
if (empty($pmp->errors)) {
$pmp
->pull(array(
'profile' => 'story',
'limit' => 1,
));
if (empty($pmp->errors) && count($pmp->query->results->docs)) {
return TRUE;
}
}
return FALSE;
}
/**
* Removes a doc from the PMP
*
* @param string $guid
* The GUID of the doc to be removed.
*/
function pmpapi_remove($guid) {
$pmp = new PMPAPIDrupal();
try {
$pmp
->delete($guid);
pmp_delete_guid_from_queue($guid);
return $pmp;
} catch (Exception $e) {
drupal_set_message(t('Error deleting doc from PMP. Deletion will be re-tried at next cron run.'), 'warning');
pmpapi_increment_delete_tries($guid);
return FALSE;
}
}
/**
* Removes a GUID from the PMPAPI_DELETE_QUEUE DrupalQueue
*
* @param string $guid
* A GUID.
*/
function pmp_delete_guid_from_queue($guid) {
$queue = DrupalQueue::get('PMPAPI_DELETE_QUEUE');
$unused_items = array();
$deleted_item = NULL;
// walk through the queue, if the GUID is already in the queue, remove it.
while ($item = $queue
->claimItem()) {
if (!empty($item->data['guid']) && $item->data['guid'] == $guid) {
$deleted_item = $item;
$queue
->deleteItem($item);
break;
}
else {
$unused_items[] = $item;
}
}
foreach ($unused_items as $item) {
$queue
->releaseItem($item);
}
return $deleted_item;
}
/**
* Increments the number of delete tries for a given GUID
*
* @param string $guid
* A GUID.
*/
function pmpapi_increment_delete_tries($guid) {
$queue = DrupalQueue::get('PMPAPI_DELETE_QUEUE');
$deleted_item = pmp_delete_guid_from_queue($guid);
$tries = !empty($deleted_item->data['tries']) ? $deleted_item->data['tries'] + 1 : 1;
// Queue the GUID so we can delete it later
if ($tries < 3) {
$fresh_item = array(
'guid' => $guid,
'tries' => $tries,
);
$queue
->createItem($fresh_item);
}
else {
watchdog('pmpapi_increment_delete_tries', 'Failed to be able to delete doc from the PMP [GUID=' . $guid . ' ] after three tries. Removing GUID from queue.');
}
}
/**
* Implements hook_cron().
*/
function pmpapi_cron() {
pmpapi_flush_delete_queue();
}
/**
* Flushes the PMPAPI_DELETE_QUEUE DrupalQueue
*/
function pmpapi_flush_delete_queue() {
$queue = DrupalQueue::get('PMPAPI_DELETE_QUEUE');
while ($item = $queue
->claimItem()) {
if (!empty($item->data['guid'])) {
$queue
->releaseItem($item);
pmpapi_remove($item->data['guid']);
}
}
}
/**
* Fetches a single PMP group from the API.
*
* @param string $guid
* A PMP GUID
*
* @return object
* A PMP doc.
*/
function pmpapi_fetch_group($guid) {
$pmp = new PMPAPIDrupal();
$pmp
->pull(array(
'guid' => $guid,
'limit' => 1000,
));
if (empty($pmp->errors) && !empty($pmp->query->results->docs[0])) {
return $pmp->query->results->docs[0];
}
return array();
}
/**
* Fetches multiple PMP groups from the API.
*
* @return array
* A list of PMP group docs.
*/
function pmpapi_fetch_groups() {
$pmp = new PMPAPIDrupal();
$params = array(
'limit' => 1000,
'profile' => 'group',
'writeable' => 'true',
);
$pmp
->pull($params);
if (empty($pmp->errors) && !empty($pmp->query->results->docs)) {
return $pmp->query->results->docs;
}
return array();
}
/**
* Clears locally cached PMP key/value pairs.
*
* @param string $key
* A key of a cache PMP value.
*/
function pmpapi_clear_pmp_cache($key = '') {
$pmp = new PMPAPIDrupal();
if (empty($pmp->errors)) {
if ($key) {
$pmp
->cacheClear($key);
}
else {
$pmp
->cacheClearAll();
}
}
}
/**
* Creates a list of all profiles.
*
* @return array
* A list of all profiles; both key and value are profile name.
*/
function pmpapi_get_profile_list() {
$info = module_invoke_all('pmpapi_profile_info');
drupal_alter('pmpapi_profile_info', $info);
$keys = array_keys($info);
return array_combine($keys, $keys);
}
/**
* Fetches profile info for a given profile name.
*
* @param $profile
* The name of a PMP profile.
*
* @return array
* The profile info, or an empty array if profile does not exist.
*/
function pmpapi_get_profile_info($profile = 'story') {
$info = module_invoke_all('pmpapi_profile_info');
drupal_alter('pmpapi_profile_info', $info);
if (!empty($info[$profile])) {
return $info[$profile];
}
return array();
}
/**
* Implements hook_pmpapi_profile_info().
*/
function pmpapi_pmpapi_profile_info() {
$pmp['story'] = array(
'title' => array(
'type' => 'text',
'accepted_types' => array(
'text',
),
'description' => t('The title of the doc.'),
'required' => TRUE,
),
'byline' => array(
'type' => 'text',
'accepted_types' => array(
'text',
),
'description' => t('Rendered byline as suggested by document distributor.'),
),
'published' => array(
'type' => 'datetime',
'accepted_types' => array(
'date',
'datetime',
'datestamp',
),
'description' => t('Display date of the document ("published" date), in ISO 8601.'),
),
'contentencoded' => array(
'type' => 'text',
'accepted_types' => array(
'text',
'text_long',
'text_with_summary',
),
'description' => t('A representation of the content which can be used literally as HTML-encoded content.'),
),
'contenttemplated' => array(
'type' => 'text',
'accepted_types' => array(
'text',
'text_long',
'text_with_summary',
),
'description' => t('A representation of the content which has placeholders for rich-media assets.'),
),
'description' => array(
'type' => 'text',
'accepted_types' => array(
'text',
'text_long',
),
'description' => t('A representation of the content of this document without HTML.'),
),
'teaser' => array(
'type' => 'text',
'accepted_types' => array(
'text',
'text_long',
),
'description' => t('A short description, appropriate for showing in small spaces.'),
),
'tags' => array(
'type' => 'array',
'accepted_types' => array(
'text',
'taxonomy_term_reference',
),
'description' => t('Tags.'),
'multiple' => TRUE,
),
'item' => array(
'type' => 'item',
'accepted_types' => array(
'image',
'file',
'entityreference',
),
'multiple' => TRUE,
),
);
$pmp['image'] = array(
'title' => array(
'type' => 'text',
'accepted_types' => array(
'text',
),
'description' => t('The title of the doc.'),
'required' => TRUE,
),
'byline' => array(
'type' => 'text',
'accepted_types' => array(
'text',
),
'description' => t('Rendered byline as suggested by document distributor.'),
),
'description' => array(
'type' => 'text',
'accepted_types' => array(
'text',
),
'description' => t('A representation of the content of this document without HTML.'),
),
);
$pmp['video'] = array(
'title' => array(
'type' => 'text',
'accepted_types' => array(
'text',
),
'description' => t('The title of the doc.'),
'required' => TRUE,
),
'description' => array(
'type' => 'text',
'accepted_types' => array(
'text',
'text_long',
),
'description' => t('A representation of the content of this document without HTML.'),
),
'teaser' => array(
'type' => 'text',
'accepted_types' => array(
'text',
'text_long',
),
'description' => t('A short description, appropriate for showing in small spaces.'),
),
'tags' => array(
'type' => 'array',
'accepted_types' => array(
'text',
'taxonomy_term_reference',
),
'description' => t('Tags.'),
'multiple' => TRUE,
),
'published' => array(
'type' => 'datetime',
'accepted_types' => array(
'date',
'datetime',
'datestamp',
),
'description' => t('Display date of the document ("published" date), in ISO 8601.'),
),
'contentencoded' => array(
'type' => 'text',
'accepted_types' => array(
'text',
'text_long',
'text_with_summary',
),
'description' => t('A representation of the content which can be used literally as HTML-encoded content.'),
),
);
$pmp['audio'] = array(
'title' => array(
'type' => 'text',
'accepted_types' => array(
'text',
),
'description' => t('The title of the doc.'),
'required' => TRUE,
),
'description' => array(
'type' => 'text',
'accepted_types' => array(
'text',
),
'description' => t('A representation of the content of this document without HTML.'),
),
);
return $pmp;
}
/**
* Implements hook_entity_load().
*/
function pmpapi_entity_load($entities, $type) {
foreach ($entities as $entity) {
$ids = entity_extract_ids($type, $entity);
$entity_id = $ids[0];
$pmp_info = db_query("SELECT guid, permissions FROM {pmpapi_local_docs} WHERE entity_type=:entity_type AND entity_id=:id", array(
':entity_type' => $type,
':id' => $entity_id,
))
->fetchAssoc();
if (!empty($pmp_info['guid'])) {
$entity->pmpapi_guid = $pmp_info['guid'];
$entity->pmpapi_permissions = unserialize($pmp_info['permissions']);
$entity->pmpapi_permissions_added = TRUE;
}
}
}
/**
* Implements hook_entity_insert().
*/
function pmpapi_entity_insert($entity, $type) {
if (!empty($entity->pmpapi_guid)) {
list($entity_id, $vid, $bundle) = entity_extract_ids($type, $entity);
$permissions = !empty($entity->pmpapi_permissions) ? serialize($entity->pmpapi_permissions) : NULL;
db_insert('pmpapi_local_docs')
->fields(array(
'entity_type' => $type,
'entity_id' => $entity_id,
'guid' => $entity->pmpapi_guid,
'permissions' => $permissions,
))
->execute();
}
}
/**
* Implements hook_entity_update().
*/
function pmpapi_entity_update($entity, $type) {
if (!empty($entity->pmpapi_guid)) {
list($entity_id, $vid, $bundle) = entity_extract_ids($type, $entity);
$permissions = !empty($entity->pmpapi_permissions) ? serialize($entity->pmpapi_permissions) : NULL;
db_merge('pmpapi_local_docs')
->key(array(
'entity_type' => $type,
))
->key(array(
'entity_id' => $entity_id,
))
->fields(array(
'guid' => $entity->pmpapi_guid,
'permissions' => $permissions,
))
->execute();
}
}
/**
* Implements hook_entity_delete().
*/
function pmpapi_entity_delete($entity, $type) {
list($entity_id, $vid, $bundle) = entity_extract_ids($type, $entity);
db_delete('pmpapi_local_docs')
->condition('entity_id', $entity_id)
->condition('entity_type', $type)
->execute();
}
/**
* Finds a matching entity id for a given GUID.
*
* @param string $guid
* A PMP GUID
*
* @return integer/FALSE
* The entity id of the entity, or FALSE, if no entity exists.
*/
function pmpapi_get_eid_from_guid($guid) {
return db_query('SELECT entity_id FROM {pmpapi_local_docs} WHERE guid=:guid', array(
':guid' => $guid,
))
->fetchField();
}
/**
* Finds a matching entity type for a given GUID.
*
* @param string $guid
* A PMP GUID
*
* @return string/FALSE
* The entity type of the entity, or FALSE, if no entity exists.
*/
function pmpapi_get_entity_type_from_guid($guid) {
return db_query('SELECT entity_type FROM {pmpapi_local_docs} WHERE guid=:guid', array(
':guid' => $guid,
))
->fetchField();
}
/**
* Finds a matching entity for a given GUID.
*
* @param string $guid
* A PMP GUID
*
* @return object/FALSE
* The entity, or NULL, if no entity exists.
*/
function pmpapi_get_entity_from_guid($guid) {
$entity = NULL;
$doc = db_query('SELECT entity_id, entity_type FROM {pmpapi_local_docs} WHERE guid=:guid', array(
':guid' => $guid,
))
->fetchAssoc();
if (!empty($doc['entity_id']) && !empty($doc['entity_type'])) {
$entities = entity_load($doc['entity_type'], array(
$doc['entity_id'],
));
if (!empty($entities)) {
$entity = array_shift($entities);
}
}
return $entity;
}
/**
* Generate a list of fields (including label as a fake field) for a given bundle.
*
* @param string $entity_type
* Name of an entity type
*
* @param string $bundle_name
* Name of an entity bundle
*
* @return array
* A list of field info (including lable as fake field, if applicable)
*/
function pmpapi_get_augmented_fields($entity_type, $bundle_name) {
$instances = field_info_instances($entity_type, $bundle_name);
$fields = array();
foreach ($instances as $instance) {
$name = $instance['field_name'];
$fields[$name] = field_info_field($name);
$fields[$name]['instance'] = $instance;
}
$entity_info = entity_get_info($entity_type);
if (!empty($entity_info['entity keys']['label'])) {
$label = $entity_info['entity keys']['label'];
$fake_field = array(
'label' => $label,
'field_name' => $label,
'type' => 'text',
'instance' => array(
'required' => TRUE,
),
);
$fields = array_merge(array(
$label => $fake_field,
), $fields);
}
return $fields;
}
/**
* Generate a list of instances (including label as a fake instance) for a given
* bundle.
*
* @param string $entity_type
* Name of an entity type
*
* @param string $bundle_name
* Name of an entity bundle
*
* @return array
* A list of instance info (including label as fake instance, if applicable)
*/
function pmpapi_get_augmented_instances($entity_type, $bundle_name) {
$instances = field_info_instances($entity_type, $bundle_name);
$entity_info = entity_get_info($entity_type);
if (!empty($entity_info['entity keys']['label'])) {
$label = $entity_info['entity keys']['label'];
$fake_instance = array(
'label' => $label,
'field_name' => $label,
'widget' => array(
'type' => 'text_textfield',
),
);
$instances = array_merge(array(
$label => $fake_instance,
), $instances);
}
return $instances;
}
/**
* Determines if a given PMP doc is valid (i.e., not embargoed nor expired)
*
* @param $doc object
* A PMP doc.
*
* @return boolean
* TRUE if doc is valid, FALSE if not.
*/
function pmpapi_doc_is_valid($doc) {
$now = pmpapi_convert_timestamp();
$from_timestamp = strtotime($doc->attributes->valid->from);
$to_timestamp = strtotime($doc->attributes->valid->to);
$from = pmpapi_convert_timestamp($from_timestamp);
$to = pmpapi_convert_timestamp($to_timestamp);
return $now >= $from && $now <= $to;
}
/**
* Converts a given timestamp to a localized PMP-friendly date.
*
* @param $timestamp int
* A timestamp.
*
* @return string
* A localized PMP-friendly date.
*/
function pmpapi_convert_timestamp($timestamp = NULL) {
if ($timestamp === NULL) {
$timestamp = REQUEST_TIME;
}
return format_date($timestamp, 'custom', DateTime::ISO8601);
}
/**
* Determines if a URL seems like an MP3
*
* @param $url
* A url pointing to the file
*
* @return bool
* TRUE if path seems to point to an M3U, FALSE otherwise
*/
function pmpapi_url_is_mp3($url) {
$pieces = drupal_parse_url($url);
return substr($pieces['path'], -4) === '.mp3';
}
/**
* Determines if a URL seems like an M3U
*
* @param $url
* A url pointing to the file
*
* @return bool
* TRUE if path seems to point to an M3U, FALSE otherwise
*/
function pmpapi_url_is_m3u($url) {
$pieces = drupal_parse_url($url);
return substr($pieces['path'], -4) === '.m3u';
}
/**
* Attempts to crack an M3U and find first link to an MP3
*
* @param $url
* A url pointing to an M3U
*
* @return
* The first MP3 URL to be found in the M3U, FALSE if no MP3 is found,
* NULL if the file cannot be opened.
*/
function pmpapi_get_mp3_from_m3u($url) {
$lines = file($url);
if ($lines) {
foreach ($lines as $line) {
if (pmpapi_url_is_mp3($line)) {
return $line;
}
}
}
else {
return NULL;
}
}
/**
* Return all PMP creators (who have created 1+ docs)
*
* @return array
* An array of creator name (key) and creator GUID (value)
*/
function pmpapi_get_creators() {
$creators = array(
'APM' => '98bf597a-2a6f-446c-9b7e-d8ae60122f0d',
'NPR' => '6140faf0-fb45-4a95-859a-070037fafa01',
'NPRDS' => '39b744ba-e132-4ef3-9099-885aef0ff2f1',
'PBS' => 'fc53c568-e939-4d9c-86ea-c2a2c70f1a99',
'PRI' => '7a865268-c9de-4b27-a3c1-983adad90921',
'PRX' => '609a539c-9177-4aa7-acde-c10b77a6a525',
);
return $creators;
}
/**
* Create a list of all PMP properties (essentially 'programs')
*
* @return array
* An array of property GUID (key) and property name (value)
*/
function pmpapi_get_properties() {
$properties = array();
$pmp = pmpapi_query(array(
'profile' => 'property',
'limit' => 10000,
));
if (!empty($pmp->query->results->docs)) {
foreach ($pmp->query->results->docs as $doc) {
$properties[$doc->attributes->guid] = $doc->attributes->title;
}
}
asort($properties);
return $properties;
}
Functions
Name | Description |
---|---|
pmpapi_clear_pmp_cache | Clears locally cached PMP key/value pairs. |
pmpapi_convert_timestamp | Converts a given timestamp to a localized PMP-friendly date. |
pmpapi_cron | Implements hook_cron(). |
pmpapi_doc_is_valid | Determines if a given PMP doc is valid (i.e., not embargoed nor expired) |
pmpapi_entity_delete | Implements hook_entity_delete(). |
pmpapi_entity_insert | Implements hook_entity_insert(). |
pmpapi_entity_load | Implements hook_entity_load(). |
pmpapi_entity_update | Implements hook_entity_update(). |
pmpapi_fetch | Fetches a single doc from the PMP. |
pmpapi_fetch_group | Fetches a single PMP group from the API. |
pmpapi_fetch_groups | Fetches multiple PMP groups from the API. |
pmpapi_flush_delete_queue | Flushes the PMPAPI_DELETE_QUEUE DrupalQueue |
pmpapi_get_augmented_fields | Generate a list of fields (including label as a fake field) for a given bundle. |
pmpapi_get_augmented_instances | Generate a list of instances (including label as a fake instance) for a given bundle. |
pmpapi_get_creators | Return all PMP creators (who have created 1+ docs) |
pmpapi_get_eid_from_guid | Finds a matching entity id for a given GUID. |
pmpapi_get_entity_from_guid | Finds a matching entity for a given GUID. |
pmpapi_get_entity_type_from_guid | Finds a matching entity type for a given GUID. |
pmpapi_get_mp3_from_m3u | Attempts to crack an M3U and find first link to an MP3 |
pmpapi_get_profile_info | Fetches profile info for a given profile name. |
pmpapi_get_profile_list | Creates a list of all profiles. |
pmpapi_get_properties | Create a list of all PMP properties (essentially 'programs') |
pmpapi_guid | Generates a GUID (UUID v4). |
pmpapi_increment_delete_tries | Increments the number of delete tries for a given GUID |
pmpapi_menu | Implements hook_menu(). |
pmpapi_permission | Implements hook_permisssion(). |
pmpapi_ping | A very, very simple health check. |
pmpapi_pmpapi_profile_info | Implements hook_pmpapi_profile_info(). |
pmpapi_query | Fetches multiple docs from the PMP, narrowed by query-type parameters. |
pmpapi_remove | Removes a doc from the PMP |
pmpapi_send | Sends a doc to the PMP. |
pmpapi_url_is_m3u | Determines if a URL seems like an M3U |
pmpapi_url_is_mp3 | Determines if a URL seems like an MP3 |
pmp_delete_guid_from_queue | Removes a GUID from the PMPAPI_DELETE_QUEUE DrupalQueue |