You are here

class MediaWysiwygFilter in Media Migration 8

Processes [[{"type":"media","fid":"1234",...}]] tokens in content.

These style tokens come from media_wysiwyg module. The regex it uses to match them for reference is:

/\[\[.+?"type":"media".+?\]\]/s


# From this
[[{"type":"media","fid":"1234",...}]]

# To this
<drupal-entity
  data-embed-button="media"
  data-entity-embed-display="view_mode:media.full"
  data-entity-type="media"
  data-entity-id="1234"></drupal-entity>
# or to this:
<drupal-media
  data-entity-type="media"
  data-view-mode="full"
  data-entity-uuid="12345678-9abc-def0-1234-56789abcdef0"></drupal-media>

Usage:

@endcode process: bar: plugin: media_wysiwyg_filter view_mode_matching: default: full media_migrations:

  • upgrade_d7_file_entity_archive
  • upgrade_d7_file_entity_image
  • upgrade_d7_file_entity_publication

file_migrations:

  • upgrade_d7_file

@endcode

Plugin annotation


@MigrateProcessPlugin(
  id = "media_wysiwyg_filter"
)

Hierarchy

Expanded class hierarchy of MediaWysiwygFilter

1 file declares its use of MediaWysiwygFilter
MediaWysiwygFilterTest.php in tests/src/Unit/Plugin/migrate/process/MediaWysiwygFilterTest.php

File

src/Plugin/migrate/process/MediaWysiwygFilter.php, line 67

Namespace

Drupal\media_migration\Plugin\migrate\process
View source
class MediaWysiwygFilter extends EmbedFilterBase implements ConfigurableInterface {

  /**
   * The migration plugin manager.
   *
   * @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
   */
  protected $migrationPluginManager;

  /**
   * Constructs a new MediaWysiwygFilter instance.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\migrate\Plugin\MigrationInterface $migration
   *   The migration entity.
   * @param \Drupal\entity_embed\EntityEmbedDisplay\EntityEmbedDisplayManager|null $entity_embed_display_manager
   *   The entity embed display plugin manager service, if available.
   * @param \Drupal\migrate\Plugin\MigrationPluginManagerInterface $migration_plugin_manager
   *   The migration plugin manager.
   * @param \Drupal\media_migration\MediaMigrationUuidOracleInterface $media_uuid_oracle
   *   The media UUID oracle.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, $entity_embed_display_manager, MigrationPluginManagerInterface $migration_plugin_manager, MediaMigrationUuidOracleInterface $media_uuid_oracle) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $media_uuid_oracle, $entity_embed_display_manager);
    $this
      ->setConfiguration($configuration);
    $this->migrationPluginManager = $migration_plugin_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
    return new static($configuration, $plugin_id, $plugin_definition, $migration, $container
      ->get('plugin.manager.entity_embed.display', ContainerInterface::NULL_ON_INVALID_REFERENCE), $container
      ->get('plugin.manager.migration'), $container
      ->get('media_migration.media_uuid_oracle'));
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    return [
      'view_mode_matching' => [],
      'media_migrations' => [],
      'file_migrations' => [],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getConfiguration() {
    return $this->configuration;
  }

  /**
   * {@inheritdoc}
   */
  public function setConfiguration(array $configuration) {

    // Merge in defaults.
    $this->configuration = NestedArray::mergeDeep($this
      ->defaultConfiguration(), $configuration);
  }

  /**
   * {@inheritdoc}
   */
  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
    if (!MediaMigration::embedTokenDestinationFilterPluginIsValid(MediaMigration::getEmbedTokenDestinationFilterPlugin())) {
      throw new MigrateException("The embed token's destination filter plugin ID is invalid.");
    }
    $pattern = '/\\[\\[\\s*(?<tag_info>\\{.+\\})\\s*\\]\\]/sU';
    if (defined(JsonDecode::class . '::ASSOCIATIVE')) {
      $decoder = new JsonDecode([
        JsonDecode::ASSOCIATIVE => TRUE,
      ]);
    }
    else {
      $decoder = new JsonDecode(TRUE);
    }
    $entity_type_id = explode(':', $this->migration
      ->getDestinationConfiguration()['plugin'])[1];
    $source_identifier = [];
    foreach ($row
      ->getSourceIdValues() as $source_id_key => $source_id_value) {
      $source_identifier[] = "{$source_id_key} {$source_id_value}";
    }
    $source_identifier = implode(', ', $source_identifier);
    $value_is_array = is_array($value);
    $text = (string) ($value_is_array ? $value['value'] : $value);
    $text = preg_replace_callback($pattern, function ($matches) use ($decoder, $entity_type_id, $source_identifier) {

      // Replace line breaks with a single space for valid JSON.
      $matches['tag_info'] = preg_replace('/\\s+/', ' ', $matches['tag_info']);
      try {
        $tag_info = $decoder
          ->decode($matches['tag_info'], JsonEncoder::FORMAT);
        if (!is_array($tag_info) || !array_key_exists('fid', $tag_info)) {
          return $matches[0];
        }

        // Find matching view mode.
        if ($this->configuration['view_mode_matching']) {
          foreach ($this->configuration['view_mode_matching'] as $key => $match) {
            if ($key == $tag_info['view_mode'] ?? NULL) {
              $tag_info['view_mode'] = $match;
            }
          }
        }
        $embed_metadata = [
          'id' => $tag_info['fid'],
          'view_mode' => $tag_info['view_mode'] ?? 'default',
        ];
        $source_attributes = !empty($tag_info['attributes']) ? $tag_info['attributes'] : [];

        // Add alt and title overrides.
        foreach ([
          'alt',
          'title',
        ] as $attribute_name) {
          if (!empty($source_attributes[$attribute_name])) {
            $embed_metadata[$attribute_name] = $source_attributes[$attribute_name];
          }
        }

        // Add alignment.
        if (!empty($source_attributes['class']) && is_string($source_attributes['class'])) {
          $alignment_map = [
            'media-wysiwyg-align-center' => 'center',
            'media-wysiwyg-align-left' => 'left',
            'media-wysiwyg-align-right' => 'right',
          ];
          $classes_array = array_unique(explode(' ', preg_replace('/\\s{2,}/', ' ', trim($source_attributes['class']))));
          foreach ($alignment_map as $original => $replacement) {
            if (in_array($original, $classes_array, TRUE)) {
              $embed_metadata['data-align'] = $replacement;
              break;
            }
          }
        }
        return $this
          ->getEmbedCode($embed_metadata) ?? $matches[0];
      } catch (NotEncodableValueException $e) {

        // There was an error decoding the JSON.
        $this
          ->messenger()
          ->addWarning(sprintf('The following media_wysiwyg token in %s %s does not have valid JSON: %s', $entity_type_id, $source_identifier, $matches[0]));
        return $matches[0];
      } catch (\LogicException $e) {
        return $matches[0];
      }
    }, $text);

    // Update fid and token in regex /file/{fid}/download?token={token}.
    if ($this->configuration['file_migrations']) {
      $pattern = '#\\/file\\/([0-9]*)\\/download\\?token=([a-zA-Z0-9]*)#';
      $replacement_template = '/file/%s/download?token=%s';
      $text = preg_replace_callback($pattern, function ($matches) use ($replacement_template) {
        $oldId = $matches[1];
        $newId = $this
          ->findDestId($oldId, $this->configuration['file_migrations']);
        $newToken = '';
        try {
          $reflector = new \ReflectionClass('Drupal\\file_entity\\Entity\\FileEntity');
          if ($reflector
            ->hasMethod('getDownloadToken') && ($file = File::load($newId))) {
            $newToken = $file
              ->getDownloadToken();
          }
        } catch (\ReflectionException $e) {
        }
        return sprintf($replacement_template, $newId, $newToken);
      }, $text);
    }
    if ($value_is_array) {
      $value['value'] = $text;
    }
    else {
      $value = $text;
    }
    return $value;
  }

  /**
   * Find new ID using the migration lookup system.
   *
   * @param int $source_id
   *   The original ID.
   * @param array $migrations
   *   The ID of the migrations to look at.
   *
   * @return int
   *   The new ID.
   */
  protected function findDestId($source_id, array $migrations) {
    try {
      $lookup_migrations = $this->migrationPluginManager
        ->createInstances($migrations);
    } catch (PluginException $exception) {
      return $source_id;
    }
    foreach ($lookup_migrations as $lookup_migration_id => $lookup_migration) {
      $source_id_values[$lookup_migration_id] = [
        $source_id,
      ];
      try {
        $destination_ids = $lookup_migration
          ->getIdMap()
          ->lookupDestinationIds($source_id_values[$lookup_migration_id]);
      } catch (MigrateException $exception) {
        continue;
      }
      if (!empty($destination_ids)) {
        return reset($destination_ids)[0];
      }
    }
    return $source_id;
  }

  /**
   * Creates the replacement token for the specified embed filter.
   */
  protected function getEmbedCode(array $embed_metadata) {
    if (empty($embed_metadata['id']) || empty($embed_metadata['view_mode'])) {
      return NULL;
    }
    $destination_filter_plugin_id = MediaMigration::getEmbedTokenDestinationFilterPlugin();
    $embed_media_reference_method = MediaMigration::getEmbedMediaReferenceMethod();
    $filter_destination_is_entity_embed = $destination_filter_plugin_id === MediaMigration::MEDIA_TOKEN_DESTINATION_FILTER_ENTITY_EMBED;
    $reference_method_is_id = $embed_media_reference_method === MediaMigration::EMBED_MEDIA_REFERENCE_METHOD_ID;
    $tag = $filter_destination_is_entity_embed ? 'drupal-entity' : 'drupal-media';

    // Add the static attributes first.
    $attributes = $filter_destination_is_entity_embed ? [
      'data-embed-button' => 'media',
    ] : [];
    $attributes['data-entity-type'] = 'media';

    // Add the attribute that references the embed media.
    $reference_attribute = $reference_method_is_id ? 'data-entity-id' : 'data-entity-uuid';
    if ($reference_method_is_id && $this->configuration['media_migrations']) {
      $embed_metadata['id'] = $this
        ->findDestId($embed_metadata['id'], $this->configuration['media_migrations']);
    }
    $attributes[$reference_attribute] = $reference_method_is_id ? $embed_metadata['id'] : $this->mediaUuidOracle
      ->getMediaUuid((int) $embed_metadata['id']);

    // Add attribute that controls how the embed media is displayed.
    $display_mode_property = $destination_filter_plugin_id === MediaMigration::MEDIA_TOKEN_DESTINATION_FILTER_ENTITY_EMBED ? 'data-entity-embed-display' : 'data-view-mode';
    $attributes[$display_mode_property] = $this
      ->getDisplayPluginId($embed_metadata['view_mode'], $destination_filter_plugin_id);

    // Alt, title, caption and align should be handled conditionally.
    $conditional_attributes = [
      'alt',
      'title',
      'data-caption',
      'data-align',
    ];
    foreach ($conditional_attributes as $conditional_attribute) {
      if (!empty($embed_metadata[$conditional_attribute])) {
        $attributes[$conditional_attribute] = $embed_metadata[$conditional_attribute];
      }
    }
    $attribute = new Attribute($attributes);
    return "<{$tag}{$attribute->__toString()}></{$tag}>";
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
EmbedFilterBase::$entityEmbedDisplayPluginManager protected property The entity embed display plugin manager service, if available.
EmbedFilterBase::$mediaUuidOracle protected property The media UUID oracle.
EmbedFilterBase::$migration protected property The actual migration plugin instance.
EmbedFilterBase::getDisplayPluginId protected function Returns the destination display plugin ID.
MediaWysiwygFilter::$migrationPluginManager protected property The migration plugin manager.
MediaWysiwygFilter::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create
MediaWysiwygFilter::defaultConfiguration public function Gets default configuration for this plugin. Overrides ConfigurableInterface::defaultConfiguration
MediaWysiwygFilter::findDestId protected function Find new ID using the migration lookup system.
MediaWysiwygFilter::getConfiguration public function Gets this plugin's configuration. Overrides ConfigurableInterface::getConfiguration
MediaWysiwygFilter::getEmbedCode protected function Creates the replacement token for the specified embed filter.
MediaWysiwygFilter::setConfiguration public function Sets the configuration for this plugin instance. Overrides ConfigurableInterface::setConfiguration
MediaWysiwygFilter::transform public function Performs the associated process. Overrides ProcessPluginBase::transform
MediaWysiwygFilter::__construct public function Constructs a new MediaWysiwygFilter instance. Overrides EmbedFilterBase::__construct
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
ProcessPluginBase::multiple public function Indicates whether the returned value requires multiple handling. Overrides MigrateProcessInterface::multiple 3
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.