Skip to content

Commit

Permalink
Issue #3137064 by jesss, mtift: Handle the "multimedia" part of the r…
Browse files Browse the repository at this point in the history
…esponse
  • Loading branch information
mtift committed Jul 14, 2020
1 parent 17a4638 commit a6cca22
Show file tree
Hide file tree
Showing 36 changed files with 926 additions and 183 deletions.
20 changes: 18 additions & 2 deletions npr_api/src/NprClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -254,13 +254,16 @@ public function parse() {
$current = $xml_iterator->current();
$key = $xml_iterator->key();

if ($key == 'image' || $key == 'audio' || $key == 'link') {
if ($key == 'image' || $key == 'audio' || $key == 'multimedia' || $key == 'link') {
if ($key == 'image') {
$parsed->{$key}[] = $this->parseSimplexmlElement($current);
}
if ($key == 'audio') {
$parsed->{$key}[] = $this->parseSimplexmlElement($current);
}
if ($key == 'multimedia') {
$parsed->{$key}[] = $this->parseSimplexmlElement($current);
}
if ($key == 'link') {
$type = $this->getAttribute($current, 'type');
$parsed->{$key}[$type] = $this->parseSimplexmlElement($current);
Expand Down Expand Up @@ -318,7 +321,20 @@ public function parse() {
}
}
break;

case 'multimedia':
// Add a placeholder for each referenced image to the body.
// But check to see if the object is multidimensional first.
if (isset($items->num)) {
$body_content[$items->num] = "[npr_multimedia:" .
$items->refId . "]";
}
else {
foreach ($items as $item) {
$body_content[$item->num] = "[npr_multimedia:" .
$item->refId . "]";
}
}
break;
default:
break;
}
Expand Down
209 changes: 206 additions & 3 deletions npr_pull/src/NprPullClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ class NprPullClient extends NprClient {
*/
protected $additionalImagesField;

/**
* The multimedia field on the story.
*
* @var string
*/
protected $multimediaField;

/**
* Create a story node.
*
Expand Down Expand Up @@ -180,14 +187,31 @@ public function addOrUpdateNode($story, $published, $display_messages = FALSE) {
// Add a reference to the media audio.
$media_audio_ids = $this->addOrUpdateMediaAudio($story);
if ($audio_field == 'unused') {
$this->nprError('This story contains audio, but the audio field for NPR stories has not been configured. Please configured it.');
$this->nprError('This story contains audio, but the audio field for NPR stories has not been configured. Please configure it.');
return;
}
if (!empty($audio_field) && $audio_field !== 'unused' && !empty($media_audio_ids)) {
foreach ($media_audio_ids as $media_audio_id) {
$this->node->{$audio_field}[] = ['target_id' => $media_audio_id];
}
}

// Make the multimedia field available to other methods.
$this->multimediaField = $story_mappings['multimedia'];
$multimedia_field = $this->multimediaField;
// Add a reference to the media audio.
$media_multimedia_ids = $this->addOrUpdateMediaMultimedia($story);
if ($multimedia_field == 'unused') {
$this->nprError('This story contains multimedia, but the multimedia field for NPR stories has not been configured. Please configure it.');
return;
}
if (!empty($multimedia_field) && $multimedia_field !== 'unused' && !empty
($media_multimedia_ids)) {
foreach ($media_multimedia_ids as $media_multimedia_id) {
$this->node->{$multimedia_field}[] = ['target_id' => $media_multimedia_id];
}
}

// Add data to the remaining fields except image and audio.
foreach ($story_mappings as $key => $value) {

Expand All @@ -210,15 +234,25 @@ public function addOrUpdateNode($story, $published, $display_messages = FALSE) {
}
elseif ($key == 'body') {
// Find any image placeholders.
preg_match_all('(\[npr_image:\d*])', $story->body,
$image_placeholders);
preg_match_all('(\[npr_image:\d*])', $story->body, $image_placeholders);

if (!empty($image_placeholders[0])) {
// Get the associated <drupal-media> tags and replace the
// placeholders in the body text.
$image_replacements = $this->replaceImages($image_placeholders[0]);
$story->body = str_replace(array_keys($image_replacements), array_values($image_replacements), $story->body);
}

// Find any multimedia placeholders.
preg_match_all('(\[npr_multimedia:\d*])', $story->body, $multimedia_placeholders);
if (!empty($multimedia_placeholders[0])) {
// Get the associated items and replace the placeholders in the
// body text.
$multimedia_replacements = $this->replaceMultimedia($multimedia_placeholders[0]);
$story->body = str_replace(array_keys($multimedia_replacements), array_values($multimedia_replacements), $story->body);
}


$this->node->set($value, [
'value' => $story->body,
'format' => $text_format,
Expand Down Expand Up @@ -420,6 +454,71 @@ protected function replaceImages(array $images) {
return $image_embed;
}

/**
* Replace multimedia items in body text.
*
* @param array $multimedia
* An array of multimedia "tokens" in the format [npr_multimedia:xxxx].
*
* @return array|null
* An array with the "token" as the key and the rendered multimedia item
* as the value, or null.
*
*/
protected function replaceMultimedia(array $multimedia) {
// Get the multimedia field information.
$multimedia_field = $this->multimediaField;

// Get the multimedia items referenced in the fields.
$referenced_multimedia = $this->node->{$multimedia_field}->referencedEntities();

// Get mappings.
$story_config = $this->config->get('npr_story.settings');
$mappings = $story_config->get('multimedia_field_mappings');
$multimedia_id_field = $mappings['multimedia_id'];
$url_field = $mappings['remote_multimedia'];

$multimedia_refs = [];
foreach ($referenced_multimedia as $multimedia_item) {
// Retrieve the npr_id for each item.
if (!empty($multimedia_id_field) && $multimedia_id_field != 'unused') {
$npr_id = $multimedia_item->get($multimedia_id_field)->value;
}

if (!empty($url_field) && $url_field != 'unused') {
$rendered_multimedia =
$multimedia_item->get($url_field)->view('default');
$rendered_multimedia = trim(render($rendered_multimedia)->__toString());
}

if (isset($npr_id) && isset($rendered_multimedia)) {
// Add rendered multimedia to an array with the NPR ID as the key.
$multimedia_refs[$npr_id] = [
'item' => $rendered_multimedia,
];
}

}


$multimedia_embed = [];
if (!empty($multimedia_refs)) {
// Loop through the multimedia items in the API response.
foreach ($multimedia as $media_item) {
// Get the NPR refId and use it to retrieve the correct multimedia item
// out of the array.
$ref_id = (int) filter_var($media_item, FILTER_SANITIZE_NUMBER_INT);
if (isset($multimedia_refs[$ref_id])) {
// Build the embedded media tag, using the original "token" as the
// array key.
$multimedia_embed[$media_item] = $multimedia_refs[$ref_id]['item'];
}
}
}

return $multimedia_embed;
}

/**
* Creates a image media item based on the configured field values.
*
Expand Down Expand Up @@ -711,6 +810,110 @@ protected function addOrUpdateMediaAudio($story) {
return $audio_ids;
}

/**
* Creates a media multimedia item based on the configured field values.
*
* The assumption here is that NPR is sending content suitable for their
* embedded, shareable JW Player. If the response is something else, this
* will likely not work as expected.
*
* @param object $story
* A single NPRMLEntity.
*
* @return array|null
* An array of multimedia media ids or null.
*/
protected function addOrUpdateMediaMultimedia($story) {

// Skip if there is no multimedia.
if (empty($story->multimedia)) {
return;
}

// Get and check the configuration.
$story_config = $this->config->get('npr_story.settings');
$multimedia_media_type = $story_config->get('multimedia_media_type');

// Get the entity manager.
$media_manager = $this->entityTypeManager->getStorage('media');

// Get, and verify, the necessary configuration.
$mappings = $this->config->get('npr_story.settings')->get('multimedia_field_mappings');
$multimedia_id_field = $mappings['multimedia_id'];
if ($multimedia_id_field == 'unused' || $mappings['multimedia_title'] == 'unused' || $mappings['remote_multimedia'] == 'unused') {
$this->nprError('Please configure the multimedia_id, multimedia_title, and remote_multimedia settings.');
return NULL;
}
$remote_multimedia_field = $mappings['remote_multimedia'];

// Create the multimedia media item(s).
foreach ($story->multimedia as $i => $multimedia) {
if (!empty($multimedia->id)) {
$uri = 'https://www.npr.org/embedded-video';
$query = [
'storyId' => $story->id,
'mediaId' => $multimedia->id,
];
$options = [
'query' => $query,
];
$multimedia_uri = URL::fromUri($uri, $options)->toString();
}
else {
return;
}

// Check to see if a story node already exists in Drupal.
if ($media_multimedia = $media_manager->loadByProperties([$multimedia_id_field => $multimedia->id])) {
if (count($media_multimedia) > 1) {
$this->nprError(
$this->t('More than one multimedia media item with the ID @id ("@title") exists. Please delete the duplicate multimedia media.', [
'@id' => $multimedia->id,
'@title' => $story->title,
]));
return;
}
$media_multimedia = reset($media_multimedia);
// Replace the multimedia field.
$media_multimedia->set($remote_multimedia_field, ['uri' => $multimedia_uri]);
$media_multimedia->set('uid', $this->config->get('npr_pull.settings')->get('npr_pull_author'));
// Clear the reference from the story node.
$this->node->set($this->multimediaField, NULL);

}
else {
// Otherwise, create a new media multimedia entity. Use the title of the
// story for the title of the multimedia.
$media_multimedia = Media::create([
$mappings['multimedia_title'] => $story->title,
'bundle' => $multimedia_media_type,
'uid' => $this->config->get('npr_pull.settings')->get('npr_pull_author'),
'langcode' => Language::LANGCODE_NOT_SPECIFIED,
$remote_multimedia_field => ['uri' => $multimedia_uri],
]);
}
// Map all of the remaining fields except title and remote_audio.
foreach ($mappings as $key => $value) {
if (!empty($value) && $value !== 'unused' && !in_array($key, ['multimedia_title', 'remote_multimedia'])) {
// ID doesn't have a "value" property.
if ($key == 'multimedia_id') {
$media_multimedia->set($value, $multimedia->id);
}
// "duration" is used by audio in config, so the key name doesn't align
elseif ($key == 'multimedia_duration') {
$media_multimedia->set($value, $multimedia->duration->value);
}
else {
$media_multimedia->set($value, $multimedia->{$key}->value);
}
}
}
$media_multimedia->save();
$multimedia_ids[] = $media_multimedia->id();
}
return $multimedia_ids;
}

/**
* Extracts an NPR ID from an NPR URL.
*
Expand Down
9 changes: 9 additions & 0 deletions npr_story/config/install/npr_story.settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ story_field_mappings:
primary_image: field_npr_primary_image
additional_images: field_npr_additional_images
audio: field_npr_audio
multimedia: field_npr_multimedia
externalAsset: field_external_assets
body: field_npr_body
byline: field_npr_byline
Expand Down Expand Up @@ -69,6 +70,14 @@ audio_field_mappings:
remote_audio: field_media_npr_remote_audio
duration: field_npr_audio_duration
rightsHolder: field_npr_audio_rights_holder
multimedia_media_type: npr_remote_multimedia
multimedia_field_mappings:
multimedia_id: field_npr_multimedia_id
multimedia_title: name
remote_multimedia: field_media_npr_multimedia
multimedia_duration: field_npr_multimedia_duration
width: field_npr_multimedia_width
height: field_npr_multimedia_height
external_asset_media_type: npr_external_asset
external_asset_field_mappings:
external_asset_title: name
Expand Down
Loading

0 comments on commit a6cca22

Please sign in to comment.