panopoly_media-8.x-2.x-dev/panopoly_media.module
panopoly_media.module
<?php
/**
* @file
* Hook implementations for Panopoly Media.
*/
use Drupal\Core\Block\BlockPluginInterface;
use Drupal\Core\Entity\EntityListBuilder;
use Drupal\Core\Form\FormStateInterface;
use Drupal\file\Entity\File;
use Drupal\media\IFrameMarkup;
use Drupal\panopoly_media\FileAccessControlHandler;
use Drupal\panopoly_media\Form\FileDeleteForm;
use Drupal\panopoly_media\Plugin\Field\FieldWidget\ImageWidget;
use Drupal\panopoly_media\Routing\FileRouteProvider;
/**
* Implements hook_theme().
*/
function panopoly_media_theme() {
return [
'media__image' => [
'base hook' => 'media',
],
'media__file' => [
'base hook' => 'media',
],
'media__video' => [
'base hook' => 'media',
],
];
}
/**
* Implements hook_block_alter().
*/
function panopoly_media_block_alter(&$definitions) {
$custom_blocks = [
'inline_block:panopoly_media_video',
];
foreach ($custom_blocks as $custom_block) {
if (isset($definitions[$custom_block])) {
$definitions[$custom_block]['category'] = t('Custom');
}
}
}
/**
* Implements hook_block_view_alter().
*/
function panopoly_media_block_view_alter(array &$build, BlockPluginInterface $block) {
if ($block->getBaseId() === 'page_title_block') {
$current_route_name = \Drupal::routeMatch()->getRouteName();
$entity_browsers = [
'panopoly_media_field_media_browser',
'panopoly_media_field_video_browser',
'panopoly_media_wysiwyg_media_browser',
];
foreach ($entity_browsers as $entity_browser) {
if ($current_route_name === "entity_browser.{$entity_browser}") {
$build['#access'] = FALSE;
break;
}
}
}
}
/**
* Implements hook_theme_registry_alter().
*/
function panopoly_media_theme_registry_alter(&$theme_registry) {
// If in Olivero, replace the HTML template for the entity browser modal.
if (isset($theme_registry['block']['preprocess functions']) && in_array('olivero_preprocess_block', $theme_registry['block']['preprocess functions'])) {
/** @var \Drupal\Core\Extension\ModuleExtensionList $moduleList */
$moduleList = \Drupal::service('extension.list.module');
// Ensure that we're using the module version of the template, and not
// one overridden in a sub-theme.
$entity_browser_iframe =& $theme_registry['html__entity_browser__modal'];
if ($entity_browser_iframe['path'] === $moduleList->getPath('entity_browser') . '/templates') {
$entity_browser_iframe['template'] = 'html--entity-browser--modal-olivero';
$entity_browser_iframe['theme path'] = $moduleList->getpath('panopoly_media');
$entity_browser_iframe['path'] = $entity_browser_iframe['theme path'] . '/templates';
}
}
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Alters the display mode offerings of the embed entity module to be more
* user friendly, and reflect what is available.
*/
function panopoly_media_form_entity_embed_dialog_alter(&$form, FormStateInterface $form_state) {
if ($form_state->get('step') == 'embed') {
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = $form_state->get('entity');
switch ($entity->bundle()) {
case 'panopoly_media_image':
$options =& $form['attributes']['data-entity-embed-display']['#options'];
$rename_options = [
'view_mode:media.embed_large' => t('Original size'),
'view_mode:media.embed_medium' => t('Quarter size'),
'view_mode:media.embed_small' => t('Thumbnail'),
'entity_reference:media_thumbnail' => t('Custom'),
];
foreach (array_keys($options) as $key) {
if (isset($rename_options[$key])) {
$options[$key] = $rename_options[$key];
}
}
$embed_display_element =& $form['attributes']['data-entity-embed-display-settings'];
if (array_key_exists('image_style', $embed_display_element)) {
foreach ($embed_display_element['image_style']['#options'] as $key => $option) {
// @todo Expose this as a setting in Panopoly settings.
if (strpos($key, 'panopoly_') === FALSE) {
unset($embed_display_element['image_style']['#options'][$key]);
}
}
}
break;
// There are no custom displays for files or videos. Force to default
// for now, until file (PDF preview) or video formatters (set size) added.
case 'panopoly_media_video':
case 'panopoly_media_file':
$form['attributes']['data-entity-embed-display']['#default_value'] = 'view_mode:media.embed_large';
$form['attributes']['data-entity-embed-display']['#access'] = FALSE;
}
}
}
/**
* Implements hook_field_formatter_info_alter().
*/
function panopoly_media_field_formatter_info_alter(&$definitions) {
if (isset($definitions['file_default']) && !in_array('image', $definitions['file_default']['field_types'])) {
$definitions['file_default']['field_types'][] = 'image';
}
}
/**
* Implements hook_field_widget_info_alter().
*/
function panopoly_media_field_widget_info_alter(array &$info) {
$info['image_image']['class'] = ImageWidget::class;
}
/**
* Implements hook_inline_entity_form_entity_form_alter().
*/
function panopoly_media_inline_entity_form_entity_form_alter(&$entity_form, &$form_state) {
// Only deal with media.
if ($entity_form['#entity_type'] != 'media') {
return;
}
$entity_form['revision_log_message']['#access'] = FALSE;
}
/**
* Implements hook_field_widget_form_alter().
*/
function panopoly_media_field_widget_form_alter(&$element, FormStateInterface $form_state, $context) {
$widgets = ['file_generic', 'image_image'];
if (in_array($context['widget']->getPluginId(), $widgets)) {
$element['#process'][] = 'panopoly_media_field_widget_process';
$element['#element_validate'][] = 'panopoly_media_widget_duplicate_validate';
}
}
/**
* Process callback for file and image widgets to add duplicate acknowledgement.
*/
function panopoly_media_field_widget_process(&$element, FormStateInterface $form_state, $form) {
$parents = $element['#parents'];
$values = $form_state->getValue($parents);
$files = File::loadMultiple($values['fids']);
$duplicate = panopoly_media_duplicate_files($files, TRUE);
$element['#panopoly_media_is_duplicate'] = $duplicate;
if ($duplicate) {
$element['panopoly_media_duplicate'] = [
'#type' => 'checkbox',
'#title' => t('Acknowledge duplicate upload'),
'#default_value' => FALSE,
];
}
return $element;
}
/**
* Determines if a file is or if set of files has a duplicate.
*
* @param \Drupal\file\FileInterface|\Drupal\file\FileInterface[] $files
* The file or files.
* @param bool $new_only
* Optional. Indicates if only new files should be checked for duplicity.
*
* @return bool
* Indicates if there is a duplicate.
*/
function panopoly_media_duplicate_files($files, $new_only = FALSE) {
// Soft dependency on filehash.
if (!\Drupal::moduleHandler()->moduleExists('filehash')) {
return FALSE;
}
// Normalize into an array.
if (!is_array($files)) {
$files = [$files];
}
// Check only newly-created files.
if ($new_only) {
$files = array_filter($files, function ($file) {
/** @var \Drupal\file\FileInterface $file */
return $file->isTemporary();
});
}
// If no files, we've got nothing to do.
if (empty($files)) {
return FALSE;
}
// Gather file IDs.
$fids = array_map(function ($file) {
/** @var \Drupal\file\FileInterface $file */
return $file->id();
}, $files);
// Check each used algorithm for duplicate.
foreach (filehash_algos() as $algo) {
$hashes = array_map(function ($file) use ($algo) {
return $file->filehash[$algo];
}, $files);
if (!$hashes) {
break;
}
// Query for duplicates.
$query = \Drupal::database()->select('filehash');
$query->addField('filehash', 'fid');
$query->condition('fid', $fids, 'NOT IN');
$query->condition($algo, $hashes, 'IN');
$query->range(0, 1);
if ($fid = $query->execute()->fetchField()) {
return TRUE;
}
}
return FALSE;
}
/**
* Validation handler for duplicate file uploads.
*/
function panopoly_media_widget_duplicate_validate(&$element, FormStateInterface &$form_state) {
// Only validate on submit.
$triggering_element = $form_state->getTriggeringElement();
if (!empty($triggering_element['#submit']) && in_array('file_managed_file_submit', $triggering_element['#submit'])) {
if (strpos($triggering_element['#name'], '_upload_button') === FALSE) {
return;
}
}
$parents = $element['#parents'];
$values = $form_state->getValue($parents);
// If there is a duplicate, verify "Acknowledge duplicate upload" box checked.
if (!empty($element['#panopoly_media_is_duplicate']) && empty($values['panopoly_media_duplicate'])) {
$form_state->setError($element, t('Duplicate file uploaded. Please check the media library for an existing file or check the "Acknowledge duplicate upload" box to continue with this upload.'));
}
}
/**
* Implements hook_entity_type_alter().
*/
function panopoly_media_entity_type_alter(array &$entity_types) {
/** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
// Allows "operations" on file entities.
if (!$entity_types['file']->hasHandlerClass('list_builder')) {
$entity_types['file']->setListBuilderClass(EntityListBuilder::class);
}
// Provides a delete form.
if (!$entity_types['file']->hasHandlerClass('form', 'delete')) {
$handlers = $entity_types['file']->getHandlerClasses();
$handlers['form']['delete'] = FileDeleteForm::class;
$entity_types['file']->setHandlerClass('form', $handlers['form']);
}
// Provides a delete form link template.
if (!$entity_types['file']->hasLinkTemplate('delete-form')) {
$entity_types['file']->setLinkTemplate('delete-form', '/file/{file}/delete');
}
// Provides routes.
if (!$entity_types['file']->hasHandlerClass('route_provider', 'html')) {
$entity_types['file']->setHandlerClass('route_provider', ['html' => FileRouteProvider::class]);
}
// Set access handler.
$entity_types['file']->setAccessClass(FileAccessControlHandler::class);
}
/**
* Implements hook_views_data_alter().
*/
function panopoly_media_views_data_alter(&$data) {
$data['file_managed']['panopoly_media_file_managed_bulk_form'] = [
'title' => t('File operations bulk form'),
'help' => t('Add a form element that lets you run operations on multiple files.'),
'field' => [
'id' => 'panopoly_media_file_managed_bulk_form',
],
];
}
/**
* Implements hook_preprocess_HOOK().
*/
function panopoly_media_preprocess_media_oembed_iframe(&$variables) {
$config = \Drupal::config('panopoly_media.settings');
if ($config->get('youtube_nocookie')) {
/** @var \Drupal\media\IFrameMarkup $media */
$html = (string) $variables['media'];
$html = str_replace('youtube.com', 'youtube-nocookie.com', $html);
$variables['media'] = IFrameMarkup::create($html);
}
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function panopoly_media_form_media_settings_form_alter(&$form) {
$config = \Drupal::config('panopoly_media.settings');
$form['panopoly_media'] = [
'#type' => 'fieldset',
'#title' => t('Panopoly Media'),
];
$form['panopoly_media']['panopoly_media_youtube_nocookie'] = [
'#type' => 'checkbox',
'#title' => t('YouTube no-cookie'),
'#description' => t("Use YouTube's privacy-enhanced mode."),
'#default_value' => $config->get('youtube_nocookie'),
];
$form['actions']['#weight'] = 101;
$form['#submit'][] = '_panopoly_media_media_settings_form_submit';
}
/**
* Submit handler for media_settings_form.
*/
function _panopoly_media_media_settings_form_submit($form, FormStateInterface $form_state) {
$config = \Drupal::configFactory()->getEditable('panopoly_media.settings');
$config->set('youtube_nocookie', $form_state->getValue('panopoly_media_youtube_nocookie'));
$config->save();
}
/**
* Implements hook_form_FORM_ID_form_alter().
*/
function panopoly_media_form_views_exposed_form_alter(&$form, FormStateInterface $form_state) {
/** @var \Drupal\views\Entity\View $view */
$view = $form_state->get('view');
if ($view->id() === 'panopoly_media_browser') {
// Reduce size from 60 to 30, so it fits better.
$form['tags']['#size'] = 30;
}
}
/**
* Implements hook_preprocess_views_view().
*/
function panopoly_media_preprocess_views_view(&$variables) {
if ($variables['view']->id() === 'panopoly_media_browser') {
$variables['view_array']['#attached']['library'][] = 'panopoly_media/panopoly_media_browser';
}
}
