acquia_dam-1.0.0-rc1/acquia_dam.module

acquia_dam.module
<?php

/**
 * @file
 * Drupal Module: Acquia DAM.
 */

declare(strict_types=1);

use Drupal\acquia_dam\Client\AcquiaDamClientFactory;
use Drupal\acquia_dam\EmbedCodeFactory;
use Drupal\acquia_dam\Entity\ComputedEmbedCodesField;
use Drupal\acquia_dam\Entity\ImageAltTextField;
use Drupal\acquia_dam\Entity\MediaExpiryDateField;
use Drupal\acquia_dam\Entity\MediaSourceField;
use Drupal\acquia_dam\Form\FocalPointMediaEditFormAlter;
use Drupal\acquia_dam\Form\MediaEmbedFormAlter;
use Drupal\acquia_dam\Form\MediaTypeFormAlter;
use Drupal\acquia_dam\FormatAllowedHtmlModifier;
use Drupal\acquia_dam\Plugin\Field\FieldType\AssetItem;
use Drupal\acquia_dam\Plugin\media\Source\Asset;
use Drupal\acquia_dam\Plugin\views\field\MediaLibrarySelectForm;
use Drupal\acquia_dam\StreamWrapper\AcquiaDamStreamWrapper;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Render\Element;
use Drupal\Core\Render\Markup;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Url;
use Drupal\filter\FilterFormatInterface;
use Drupal\media\Entity\Media;
use Drupal\media\Entity\MediaType;
use Drupal\media\MediaInterface;
use Drupal\media\MediaTypeInterface;
use Drupal\media_library\MediaLibraryState;
use Drupal\media_library\Plugin\Field\FieldWidget\MediaLibraryWidget;
use Drupal\views\Form\ViewsForm;
use Drupal\views\Plugin\views\cache\CachePluginBase;
use Drupal\views\ViewExecutable;

/**
 * Implements hook_theme().
 */
function acquia_dam_theme($existing, $type, $theme, $path) {
  return [
    'acquia_dam_embed_select_form' => [
      'render element' => 'form',
    ],
    'acquia_dam_iframe_responsive' => [
      'variables' => [
        'src' => NULL,
      ],
    ],
    'acquia_dam_video_stream' => [
      'variables' => [
        'attributes' => NULL,
        'source_attributes' => NULL,
      ],
    ],
  ];
}

/**
 * Implements hook_entity_field_storage_info().
 */
function acquia_dam_entity_field_storage_info(EntityTypeInterface $entity_type): array {
  $definitions = [];
  if ($entity_type->id() === 'media') {
    $definitions[MediaSourceField::SOURCE_FIELD_NAME] = MediaSourceField::getStorageDefinition($entity_type->id());
    $definitions[MediaExpiryDateField::EXPIRY_DATE_FIELD_NAME] = MediaExpiryDateField::getStorageDefinition($entity_type->id());
    $definitions[ComputedEmbedCodesField::FIELD_NAME] = ComputedEmbedCodesField::getStorageDefinition($entity_type->id());
    $definitions[ImageAltTextField::IMAGE_ALT_TEXT_FIELD_NAME] = ImageAltTextField::getStorageDefinition($entity_type->id());
  }
  return $definitions;
}

/**
 * Implements hook_entity_bundle_field_info().
 */
function acquia_dam_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
  $definitions = [];
  if ($entity_type->id() === 'media') {
    $media_type_storage = Drupal::entityTypeManager()->getStorage('media_type');
    $media_type = $media_type_storage->load($bundle);
    // @todo this check vs an `assert` is needed due to MediaLibrarySelectForm.
    //   It can create media entity stubs with invalid bundles when the view
    //   is not properly filtered. This should only happen when editing the
    //   View and the MediaLibrarySelectForm is rendered and non-functional.
    if (!$media_type instanceof MediaTypeInterface) {
      return $definitions;
    }
    $source = $media_type->getSource();
    if ($source instanceof Asset) {
      $definitions[MediaSourceField::SOURCE_FIELD_NAME] = MediaSourceField::getFieldDefinition(
        $entity_type->id(),
        $bundle,
        (string) $media_type->label()
      );
      $definitions[MediaExpiryDateField::EXPIRY_DATE_FIELD_NAME] = MediaExpiryDateField::getFieldDefinition(
        $entity_type->id(),
        $bundle,
        (string) $media_type->label()
      );
      $definitions[ComputedEmbedCodesField::FIELD_NAME] = ComputedEmbedCodesField::getFieldDefinition(
        $entity_type->id(),
        $bundle
      );
      if ($source->getDerivativeId() === 'image') {
        $definitions[ImageAltTextField::IMAGE_ALT_TEXT_FIELD_NAME] = ImageAltTextField::getFieldDefinition(
          $entity_type->id(),
          $bundle,
          (string) $media_type->label()
        );
      }
    }
  }
  return $definitions;
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function acquia_dam_form_editor_media_dialog_alter(&$form, FormStateInterface $form_state) {
  $form_alter = \Drupal::classResolver()
    ->getInstanceFromDefinition(MediaEmbedFormAlter::class);
  assert($form_alter instanceof MediaEmbedFormAlter);
  $form_alter->formAlter($form, $form_state);
}

/**
 * Implements hook_form_BASE_FORM_ID_alter().
 */
function acquia_dam_form_media_type_form_alter(&$form, FormStateInterface $form_state) {
  $form_alter = \Drupal::classResolver()
    ->getInstanceFromDefinition(MediaTypeFormAlter::class);
  assert($form_alter instanceof MediaTypeFormAlter);
  $form_alter->formAlter($form, $form_state);
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function acquia_dam_form_media_acquiadam_config_alter(&$form, FormStateInterface $form_state) {
  $form['authentication'] = [
    '#type' => 'fieldset',
    '#title' => t('Authentication details'),
  ];
  $form['authentication']['redirect'] = [
    "#markup" => "The site credentials to your Acquia DAM account are now under " . Link::createFromRoute(t('Acquia DAM'), 'acquia_dam.config')->toString(),
  ];
}

/**
 * Implements hook_preprocess_HOOK().
 */
function acquia_dam_preprocess_media(&$variables) {
  if ($variables['view_mode'] === 'media_library') {
    $variables['attributes']['class'][] = 'contextual-region';
  }
  // We change how to render only if 'data-embed-code-id' attribute is set.
  // Otherwise, we let the view mode configuration handle rendering.
  if (isset($variables['attributes']['data-embed-code-id'])) {
    $media = $variables['media'];
    assert($media instanceof MediaInterface);
    $media_type = MediaType::load($media->bundle());
    assert($media_type instanceof MediaTypeInterface);
    $source = $media_type->getSource();
    if ($source instanceof Asset) {
      $embeds = $source->getMetadata($media, 'embeds');
      if (empty($embeds)) {
        return;
      }
      $variables['content'][MediaSourceField::SOURCE_FIELD_NAME][0] =
        EmbedCodeFactory::renderAsset(
          $variables['attributes']['data-embed-code-id'],
          $media
        );
      unset($variables['attributes']['data-embed-code-id']);
    }
  }
}

/**
 * Implements hook_theme_suggestions_HOOK().
 *
 * Each theme in Drupal core provides a template for the view provided by Media
 * Library based on its identifier. We need to provide that theme hook
 * suggestion for our own view so that it is templated correctly.
 */
function acquia_dam_theme_suggestions_views_view_unformatted(array $variables) {
  $suggestions = [];
  if ($variables['view']->id() === 'acquia_dam_asset_library') {
    $suggestions[] = 'views_view_unformatted__media_library';
  }
  return $suggestions;
}

/**
 * Implements hook_theme_suggestions_HOOK().
 */
function acquia_dam_theme_suggestions_views_view(array $variables) {
  $suggestions = [];
  if ($variables['view']->id() === 'acquia_dam_asset_library') {
    $suggestions[] = 'views_view__media_library';
  }
  return $suggestions;
}

/**
 * Implements hook_views_post_render().
 *
 * Media Library comes with few preprocess that takes care of adding necessary
 * libraries into the page. Unfortunately it is only applicable for
 * media_library view, this will take extending to acquia_dam_assest_library as
 * well.
 */
function acquia_dam_views_post_render(ViewExecutable $view, &$output, CachePluginBase $cache) {
  if ($view->id() === 'acquia_dam_asset_library') {
    $output['#attached']['library'][] = 'media_library/view';
    if (strpos($view->current_display, 'widget') === 0) {
      try {
        $query = MediaLibraryState::fromRequest($view->getRequest())->all();
      }
      catch (InvalidArgumentException $e) {
        // MediaLibraryState::fromRequest() will throw an exception if the view
        // is being previewed, since not all required query parameters will be
        // present. In a preview, however, this can be omitted since we're
        // merely previewing.
        // @todo Use the views API for checking for the preview mode when it
        //   lands. https://www.drupal.org/project/drupal/issues/3060855
        if (empty($view->preview) && empty($view->live_preview)) {
          throw $e;
        }
      }
      // If the current query contains any parameters we use to contextually
      // filter the view, ensure they persist across AJAX rebuilds.
      // The ajax_path is shared for all AJAX views on the page, but our query
      // parameters are prefixed and should not interfere with any other views.
      // @todo Rework or remove this in https://www.drupal.org/node/2983451
      if (!empty($query)) {
        $ajax_path = &$output['#attached']['drupalSettings']['views']['ajax_path'];
        $parsed_url = UrlHelper::parse($ajax_path);
        $query = array_merge($query, $parsed_url['query']);
        $ajax_path = $parsed_url['path'] . '?' . UrlHelper::buildQuery($query);
      }
    }
  }
}

/**
 * Implements hook_views_pre_render().
 *
 * This will take care of necessary classes which is added by the media_library
 * to its view is extended to `acquia_dam_asset_library` as well.
 */
function acquia_dam_views_pre_render(ViewExecutable $view) {
  $add_classes = function (&$option, array $classes_to_add) {
    $classes = $option ? preg_split('/\s+/', trim($option)) : [];
    $classes = array_filter($classes);
    $classes = array_merge($classes, $classes_to_add);
    $option = implode(' ', array_unique($classes));
  };

  if ($view->id() === 'acquia_dam_asset_library') {
    if (isset($view->display_handler->options['defaults']['css_class']) &&
      $view->display_handler->options['defaults']['css_class']) {
      $add_classes($view->displayHandlers->get('default')->options['css_class'], ['media-library-view']);
    }
    else {
      $add_classes($view->display_handler->options['css_class'], ['media-library-view']);
    }

    if (strpos($view->current_display, 'widget') === 0) {
      // Logic from claro.theme preprocess all of this will be remove once we
      // can make the view id configurable.
      if (array_key_exists('thumbnail', $view->field)) {
        $add_classes($view->field['thumbnail']->options['element_class'], ['media-library-item__content']);
      }
      if (array_key_exists('media_library_select_form', $view->field)) {
        $add_classes($view->field['media_library_select_form']->options['element_wrapper_class'], ['media-library-item__click-to-select-checkbox']);
      }

      if ($view->display_handler->options['defaults']['css_class']) {
        $add_classes($view->displayHandlers->get('default')->options['css_class'], ['media-library-view--widget']);
      }
      else {
        $add_classes($view->display_handler->options['css_class'], ['media-library-view--widget']);
      }

      if (array_key_exists('media_library_select_form', $view->field)) {
        $add_classes($view->field['media_library_select_form']->options['element_wrapper_class'], ['js-click-to-select-checkbox']);
      }
      $add_classes($view->display_handler->options['css_class'], ['js-media-library-view']);
    }

    $add_classes(
      $view->style_plugin->options['row_class'],
      ['js-media-library-item', 'js-click-to-select']
    );

    // NOTE: modified from core to bypass undefined offset in our View.
    if (!empty($view->display_handler->options['defaults']['css_class'])) {
      $add_classes($view->displayHandlers->get('default')->options['css_class'], ['js-media-library-view']);
    }
    else {
      $add_classes($view->display_handler->options['css_class'], ['js-media-library-view']);
    }
  }
}

/**
 * Implements hook_preprocess_views_view_fields().
 *
 * This will take care of necessary classes which is added by the media_library
 * to its view is extended to `acquia_dam_asset_library` as well.
 */
function acquia_dam_preprocess_views_view_fields(&$variables) {
  // Add classes to media rendered entity field so it can be targeted for
  // JavaScript mouseover and click events.
  if ($variables['view']->id() === 'acquia_dam_asset_library' && isset($variables['fields']['rendered_entity'])) {
    if (isset($variables['fields']['rendered_entity']->wrapper_attributes)) {
      $variables['fields']['rendered_entity']->wrapper_attributes->addClass('js-click-to-select-trigger');
      // @see function claro_preprocess_views_view_fields__media_library(array &$variables).
      $variables['fields']['rendered_entity']->wrapper_attributes->addClass('media-library-item__click-to-select-trigger');

    }
  }
}

/**
 * Alter the bulk form to add a more accessible label.
 *
 * @param array $form
 *   An associative array containing the structure of the form.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The current state of the form.
 *
 * @todo Remove in https://www.drupal.org/node/2983454
 */
function acquia_dam_form_views_form_acquia_dam_asset_library_page_alter(array &$form, FormStateInterface $form_state) {
  if (isset($form['media_bulk_form']) && isset($form['output'])) {
    /** @var \Drupal\views\ViewExecutable $view */
    $view = $form['output'][0]['#view'];
    foreach (Element::getVisibleChildren($form['media_bulk_form']) as $key) {
      if (isset($view->result[$key])) {
        $media = $view->field['media_bulk_form']->getEntity($view->result[$key]);
        $form['media_bulk_form'][$key]['#title'] = t('Select @label', [
          '@label' => $media->label(),
        ]);
      }
    }
  }
}

/**
 * Implements hook_ENTITY_TYPE_insert().
 */
function acquia_dam_entity_view_display_insert(EntityViewDisplayInterface $display) {
  // Adjust our media type's media library view displays.
  // @see _media_library_configure_view_display().
  if ($display->getTargetEntityTypeId() === 'media' && $display->getMode() === 'media_library') {
    $media_type = MediaType::load($display->getTargetBundle());
    if ($media_type && $media_type->getSource() instanceof Asset) {
      $display->setComponent('thumbnail', [
        'type' => 'acquia_dam_thumbnail',
        'label' => 'hidden',
        'settings' => [
          'thumbnail_size' => '300px',
        ],
      ]);
      $display->save();
    }
  }
}

/**
 * Implements hook_form_BASE_FORM_ID_alter().
 */
function acquia_dam_form_media_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
  /** @var \Drupal\acquia_dam\Plugin\media\Source\Asset $asset */
  $asset = $form_state->getFormObject()->getEntity()->getSource();
  $is_dam_asset = $asset instanceof Asset;

  if (!$is_dam_asset) {
    return;
  }

  // Disable add form save button for DAM assets.
  if (str_ends_with($form_id, '_add_form')) {
    \Drupal::messenger()->addWarning('DAM assets cannot be added from this form, only through the media library when creating content.');
    $form['actions']['submit']['#disabled'] = TRUE;
  }

  $focal_point_installed = \Drupal::moduleHandler()->moduleExists('focal_point');
  if ($focal_point_installed && str_ends_with($form_id, '_edit_form') && $asset->getDerivativeId() === 'image') {
    $form_alter = \Drupal::classResolver()
      ->getInstanceFromDefinition(FocalPointMediaEditFormAlter::class);
    assert($form_alter instanceof FocalPointMediaEditFormAlter);
    $form_alter->formAlter($form, $form_state);
  }
}

/**
 * Implements hook_form_alter().
 */
function acquia_dam_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
  // Add a process callback to ensure that the media library view's exposed
  // filters submit button is not moved to the modal dialog's button area.
  $form_object = $form_state->getFormObject();

  // Add class to the Media Library views form.
  if ($form_object instanceof ViewsForm && strpos($form_object->getBaseFormId(), 'views_form_acquia_dam_asset_library_widget') === 0) {
    // The conditional below exists because the media-library-views-form class
    // is currently added by Classy, but Umami will eventually not use Classy as
    // a base theme.
    // @todo remove conditional, keep class addition in
    //   https://drupal.org/node/3110137
    // @see https://www.drupal.org/node/3109287
    // @see classy_form_alter()
    if (!isset($form['#attributes']['class']) || !in_array('media-library-views-form', $form['#attributes']['class'])) {
      $form['#attributes']['class'][] = 'media-library-views-form';
    }
  }

  if ($form_id === 'views_exposed_form' && strpos($form['#id'], 'views-exposed-form-acquia-dam-asset-library-widget') === 0) {
    $form['#after_build'][] = '_acquia_dam_views_form_media_library_after_build';
    // Button or action #type won't work because that might trigger their own
    // request. Thereby breaking the view with empty conditions.
    // @see Drupal.views.ajaxView.prototype.attachExposedFormAjax.
    // @see https://www.drupal.org/project/drupal/issues/2804277.
    $form['clear'] = [
      '#type' => 'markup',
      '#markup' => '<a href="#" class="button views-exposed-form__item views-exposed-form__item--actions  acquia-dam-clear-filter">Clear Filter</a>',
    ];
  }
  elseif ($form_id === 'user_form') {
    // Reverting the changes set in media_acquiadam_form_user_form_alter.
    if (\Drupal::moduleHandler()->moduleExists('media_acquiadam')) {
      unset($form['media_acquiadam']);
      if (in_array('media_acquiadam_unauthorize', $form['actions']['submit']['#submit'])) {
        $key = array_search('media_acquiadam_unauthorize', $form['actions']['submit']['#submit']);
        unset($form['actions']['submit']['#submit'][$key]);
      }
    }
  }

}

/**
 * Form #after_build callback for media_library view's exposed filters form.
 */
function _acquia_dam_views_form_media_library_after_build(array $form, FormStateInterface $form_state) {
  // Remove .form-actions from the view's exposed filter actions. This prevents
  // the "Apply" submit button from being moved into the dialog's
  // button area.
  // @see \Drupal\Core\Render\Element\Actions::processActions
  // @see Drupal.behaviors.dialog.prepareDialogButtons
  // @todo Remove this after
  //   https://www.drupal.org/project/drupal/issues/3089751 is fixed.
  if (($key = array_search('form-actions', $form['actions']['#attributes']['class'])) !== FALSE) {
    unset($form['actions']['#attributes']['class'][$key]);
  }
  return $form;
}

/**
 * Implements hook_ENTITY_TYPE_presave().
 *
 * Ensures `data-embed-code-id` is present for filter_html and drupal-media.
 *
 * We use hook_presave due to ConfigEntityBase::preSave crashing on re-save
 * during the hook_insert hook.
 */
function acquia_dam_filter_format_presave(FilterFormatInterface $filter_format) {
  \Drupal::classResolver()
    ->getInstanceFromDefinition(FormatAllowedHtmlModifier::class)
    ->process($filter_format);
}

/**
 * Implements hook_ENTITY_TYPE_insert().
 *
 * Register integration link on Acquia DAM when media gets created.
 */
function acquia_dam_media_insert(MediaInterface $entity) {
  $source = $entity->getSource();
  if (!str_starts_with($source->getPluginId(), 'acquia_dam_asset')) {
    return;
  }

  $asset_id = $entity->get('acquia_dam_asset_id')->first()->getValue();

  if (empty($asset_id['asset_id'])) {
    return;
  }

  /** @var \Drupal\acquia_dam\IntegrationLinkRegister $register */
  $register = \Drupal::service('acquia_dam.integration_link_register');
  $register->addIntegrationLinksList($asset_id['asset_id'], $entity);
}

/**
 * Implements hook_cron().
 *
 * Refresh acquia_dam versions.
 */
function acquia_dam_cron() {
  \Drupal::service('acquia_dam.cron')->run();
}

/**
 * Implements hook_ENTITY_TYPE_delete().
 *
 * Remove integration link from Acquia DAM when media gets deleted.
 */
function acquia_dam_media_delete(MediaInterface $entity) {
  /** @var \Drupal\acquia_dam\Plugin\media\Source\Asset $source */
  $source = $entity->getSource();
  if (!$source instanceof Asset) {
    return;
  }

  $source_field = $entity->get(MediaSourceField::SOURCE_FIELD_NAME);
  $source_field_item = $source_field->first();
  assert($source_field_item instanceof AssetItem);
  Cache::invalidateTags(["acquia-dam-asset:{$source_field_item->asset_id}"]);

  $module_handler = \Drupal::service('module_handler');
  if ($source->getDerivativeId() === 'image' && $module_handler->moduleExists('crop')) {
    /** @var \Drupal\acquia_dam\ImageStyleHelper $image_style_helper */
    $image_style_helper = \Drupal::service('acquia_dam.image_style_support');
    if ($crops = $image_style_helper->getCrops($entity)) {
      foreach ($crops as $crop) {
        $crop->delete();
      }
    }
  }

  /** @var \Drupal\acquia_dam\IntegrationLinkRegister $register */
  $register = \Drupal::service('acquia_dam.integration_link_register');
  foreach ($register->getAllEntityUuuidsIntegratingAsset($source_field_item->asset_id) as $entity_uuid) {
    $register->addIntegrationToDeleteList($entity_uuid);
  }
}

/**
 * Implements hook_menu_links_discovered_alter().
 */
function acquia_dam_menu_links_discovered_alter(array &$links) {
  if (isset($links['media_acquiadam.config'])) {
    $links['media_acquiadam.config']['title'] = new TranslatableMarkup('Acquia DAM Entity Browser');
    $links['media_acquiadam.config']['description'] = new TranslatableMarkup('Configure Acquia DAM for the Entity Browser module.');
    $links['media_acquiadam.config']['weight'] = 0;
    $links['acquia_dam.config']['weight'] = -1;
  }
}

/**
 * Implements hook_module_implements_alter().
 */
function acquia_dam_module_implements_alter(&$implementations, $hook) {
  if ($hook == 'form_alter') {
    // Move acquia_dam_form_alter() to the end of the list.
    $group = $implementations['acquia_dam'];
    unset($implementations['acquia_dam']);
    $implementations['acquia_dam'] = $group;
  }
}

/**
 * Implements hook_preprocess_media_library_wrapper().
 */
function acquia_dam_preprocess_media_library_wrapper(array &$variables) {
  $variables['attributes']['class'][] = 'acquia-dam-media-library';
}

/**
 * Implements hook_library_info_alter().
 */
function acquia_dam_library_info_alter(&$libraries, $extension) {
  if ($extension === 'acquia_dam') {
    $admin_theme = \Drupal::configFactory()->get('system.theme')->get('admin');
    if ($admin_theme === 'acquia_claro') {
      $libraries['media_library.style']['css']['theme']['css/media-library-acquia-claro.css'] = [];
    }
    elseif ($admin_theme === 'gin') {
      $libraries['media_library.style']['css']['theme']['css/media-library-gin.css'] = [];
    }
  }
}

/**
 * Implements hook_views_plugins_field_alter().
 */
function acquia_dam_views_plugins_field_alter(array &$plugins) {
  if (isset($plugins['media_library_select_form'])) {
    $plugins['media_library_select_form']['class'] = MediaLibrarySelectForm::class;
  }
}

/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function acquia_dam_media_presave(MediaInterface $media) {
  if ($media->isNew() && $media->getSource() instanceof Asset) {
    $source_field = $media->get(MediaSourceField::SOURCE_FIELD_NAME);
    if ($source_field->isEmpty()) {
      return;
    }
    $source_field_item = $source_field->first();
    assert($source_field_item instanceof AssetItem);

    if (empty($source_field_item->version_id)) {
      $client_factory = \Drupal::service('acquia_dam.client.factory');
      assert($client_factory instanceof AcquiaDamClientFactory);
      $client = $client_factory->getSiteClient();
      $asset_versions = $client->getAssetVersionList($source_field_item->asset_id);

      $versions = $asset_versions['versions'];
      usort($versions, function ($a, $b) {
        return $a['dateLastEdited'] <=> $b['dateLastEdited'];
      });

      $source_field_item->version_id = end($versions)['uuid'];
    }

    if (empty($source_field_item->external_id)) {
      $source = $media->getSource();
      if ($source instanceof Asset) {
        $source_field_item->external_id = $source->getMetadata($media, "external_id");
      }
    }

  }
}

/**
 * Implements hook_preprocess_links__media_library_menu().
 *
 * This targets the menu of available media types in the media library's modal
 * dialog.
 *
 * @todo Do this in the relevant template once
 *   https://www.drupal.org/project/drupal/issues/3088856 is resolved.
 */
function acquia_dam_preprocess_links__media_library_menu(array &$variables) {
  foreach ($variables['links'] as &$link) {
    // Add a class to the Media Library menu items.
    $link['attributes']->addClass('media-library-menu__item');

    // This conditional exists because the media-library-menu__link class is
    // currently added by Classy, but Claro will eventually not use Classy as a
    // base theme.
    // @todo remove conditional, keep class addition in
    //   https://drupal.org/node/3110137
    // @see classy_preprocess_links__media_library_menu()
    if (!isset($link['link']['#options']['attributes']['class']) || !in_array('media-library-menu__link', $link['link']['#options']['attributes']['class'])) {
      $link['link']['#options']['attributes']['class'][] = 'media-library-menu__link';
    }
  }
}

/**
 * Implements hook_filter_info_alter().
 */
function acquia_dam_filter_info_alter(array &$info) {
  if (isset($info['media_embed'])) {
    $info['media_embed']['class'] = '\Drupal\acquia_dam\Plugin\Filter\DamMediaEmbed';
  }

}

/**
 * Implements hook_editor_js_settings_alter().
 */
function acquia_dam_editor_js_settings_alter(array &$settings) {
  // CKEditor always sorts plugins and does not have a mechanism for altering
  // dependencies. This makes it impossible for our `mediarevisions` plugin
  // to add its hooks before `drupalmedia` is loaded.
  if (isset($settings['editor']['formats']) && !is_array($settings['editor']['formats'])) {
    return;
  }
  foreach ($settings['editor']['formats'] as $editor => $setting) {
    if (!is_array($setting) || !isset($setting['editor'])) {
      continue;
    }
    if (!isset($setting['editorSettings']) || !is_array($setting['editorSettings'])) {
      continue;
    }
    $editor_settings = $setting['editorSettings'];
    // Make sure the media revisions plugin loads in correct order.
    if ($setting['editor'] === 'ckeditor') {
      if (!isset($editor_settings['extraPlugins']) || !is_string($editor_settings['extraPlugins'])) {
        continue;
      }

      $plugins = explode(',', $editor_settings['extraPlugins']);
      foreach (['acquia_dam_mediarevisions', 'acquia_dam_mediaexpiration'] as $plugin) {
        $acquia_dam_mediarevisions_index = array_search($plugin, $plugins, TRUE);
        if ($acquia_dam_mediarevisions_index === FALSE) {
          continue;
        }
        unset($plugins[$acquia_dam_mediarevisions_index]);
        array_unshift($plugins, $plugin);
      }
      $settings['editor']['formats'][$editor]['editorSettings']['extraPlugins'] = implode(',', $plugins);
    }
    // Remove asset media types from the viewMode dropdown.
    // @note the button isn't completely hidden
    // @see https://www.drupal.org/project/drupal/issues/3300568
    elseif ($setting['editor'] === 'ckeditor5') {
      $media_types = MediaType::loadMultiple();
      $asset_media_types = array_filter($media_types, static function (MediaTypeInterface $media_type) {
        return $media_type->getSource() instanceof Asset;
      });
      if (!isset($editor_settings['config']['drupalElementStyles']['viewMode']) || !is_array($editor_settings['config']['drupalElementStyles']['viewMode'])) {
        continue;
      }
      $view_mode_items = $editor_settings['config']['drupalElementStyles']['viewMode'];
      foreach ($view_mode_items as $key => $view_mode_item) {
        $view_mode_items[$key]['modelAttributes']['drupalMediaType'] = array_values(array_diff(
          $view_mode_item['modelAttributes']['drupalMediaType'],
          array_keys($asset_media_types)
        ));
      }
      $settings['editor']['formats'][$editor]['editorSettings']['config']['drupalElementStyles']['viewMode'] = $view_mode_items;
    }
  }
}

/**
 * Implements hook_entity_operation().
 */
function acquia_dam_entity_operation(EntityInterface $entity) {
  $operations = [];

  $entityTypeId = $entity->getEntityTypeId();
  if ($entityTypeId !== 'media') {
    return $operations;
  }
  /** @var \Drupal\media\MediaInterface $entity */
  $asset = $entity->getSource();
  if (!$asset instanceof Asset) {
    return $operations;
  }

  if ($asset->getDerivativeId() === 'image') {
    $updateUrl = Url::fromRoute('acquia_dam.version_update', ['media' => $entity->id()]);
    $operations['version_update'] = [
      'title' => t('Check for update'),
      'weight' => -1,
      'url' => $updateUrl,
    ];
  }

  $operations['metadata_sync'] = [
    'title' => t('Sync metadata'),
    'url' => Url::fromRoute('acquia_dam.metadata_sync', ['media' => $entity->id()]),
  ];

  return $operations;
}

/**
 * Implements hook_field_widget_single_element_form_alter().
 */
function acquia_dam_field_widget_single_element_form_alter(array &$element, FormStateInterface $form_state, array $context) {
  if ($context['widget'] instanceof MediaLibraryWidget) {
    $selections = Element::children($element['selection']);
    $element['#attached']['library'][] = 'acquia_dam/acquia_dam.expired_assets';
    $current_time = \Drupal::time()->getCurrentTime();
    $svg = file_get_contents(\Drupal::service('extension.list.module')->getPath('acquia_dam') . '/images/alert-red.svg');
    foreach ($selections as $selection) {
      /** @var \Drupal\media\Entity\Media $media*/
      $media = $element['selection'][$selection]['rendered_entity']['#media'];
      $media = $media->isLatestRevision() ? $media : Media::load($media->id());
      if (!$media->getSource() instanceof Asset) {
        continue;
      }
      $expiry_date = $media->get('acquia_dam_expiry_date')->getValue();
      if (!$expiry_date) {
        continue;
      }
      if ((int) $expiry_date[0]['value'] < $current_time) {
        $expiry_build = [
          '#type' => 'inline_template',
          '#template' => '<div class="acquia-dam-expired-asset-container"><div class="acquia-dam-expired-asset">{{ svg }}<div class="acquia-dam-asset-expired__popper">{{ description }}</div></div></div>',
          '#context' => [
            'description' => t("The media is expired and won't be seen by content viewers. Please remove existing media and add new media."),
            'svg' => Markup::create($svg),
          ],
        ];
        array_unshift($element['selection'][$selection], $expiry_build);
      }
    }
  }
}

/**
 * Implements hook_preprocess_responsive_image().
 */
function acquia_dam_preprocess_responsive_image(&$variables) {
  $wrapper = \Drupal::service('stream_wrapper_manager')->getViaUri($variables['uri']);
  if ($wrapper instanceof AcquiaDamStreamWrapper) {
    // The `acquia-dam://` URI does not append an extension, since the format
    // may be optimized on the CDN (`web` format.) We need to remove the default
    // `type` attribute when uses `application/octet-stream` when an extension
    // is not part of the URI.
    foreach ($variables['sources'] as $source) {
      /** @var \Drupal\Core\Template\Attribute $source */
      $source->removeAttribute('type');
    }
  }
}

/**
 * Prepares variables for acquia_dam_video_stream templates.
 *
 * Default template: acquia-dam-video-stream.html.twig.
 *
 * @param array $variables
 *   An associative array containing:
 *   - attributes: An array of HTML attributes, intended to be added to the
 *     video tag.
 *   - source_attributes: An array of HTML attributes for to be added to the
 *     source tag.
 */
function template_preprocess_acquia_dam_video_stream(array &$variables) {
  if (!isset($variables['source_attributes']) || empty($variables['source_attributes'])) {
    return;
  }

  $variables['source_attributes'] = new Attribute($variables['source_attributes']);
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc