media_migration-8.x-1.x-dev/src/MigratePluginAlterer.php

src/MigratePluginAlterer.php
<?php

namespace Drupal\media_migration;

use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\field\Plugin\migrate\source\d7\Field;
use Drupal\field\Plugin\migrate\source\d7\FieldInstance;
use Drupal\field\Plugin\migrate\source\d7\ViewMode;
use Drupal\media_migration\Plugin\MediaWysiwyg\Paragraphs;
use Drupal\migmag\Utility\MigMagMigrationUtility;
use Drupal\migmag\Utility\MigMagSourceUtility;
use Drupal\migrate\Exception\RequirementsException;
use Drupal\migrate\Plugin\RequirementsInterface;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\FieldMigration;
use Psr\Log\LoggerInterface;

/**
 * Service for performing migration plugin alterations.
 */
class MigratePluginAlterer {

  /**
   * The plugin.manager.media_wysiwyg service.
   *
   * @var \Drupal\media_migration\MediaWysiwygPluginManager
   */
  protected $pluginManagerMediaWysiwyg;

  /**
   * The logger.
   *
   * @var \Psr\Log\LoggerInterface
   */
  protected $logger;

  /**
   * The module handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected $moduleHandler;

  /**
   * Constructs a MigratePluginAlterer object.
   *
   * @param \Drupal\media_migration\MediaWysiwygPluginManager $plugin_manager_media_wysiwyg
   *   The Media WYSIWYG plugin manager.
   * @param \Psr\Log\LoggerInterface $logger
   *   The logger.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler.
   */
  public function __construct(MediaWysiwygPluginManager $plugin_manager_media_wysiwyg, LoggerInterface $logger, ModuleHandlerInterface $module_handler) {
    $this->pluginManagerMediaWysiwyg = $plugin_manager_media_wysiwyg;
    $this->logger = $logger;
    $this->moduleHandler = $module_handler;
  }

  /**
   * Alters migrate plugins.
   *
   * @param array $migrations
   *   The array of migration plugins.
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginException
   *   If a plugin cannot be found.
   */
  public function alter(array &$migrations) {
    $this->alterFieldMigrations($migrations);
    $this->addMediaWysiwygProcessor($migrations);
    $this->alterFilterFormatMigration($migrations);
  }

  /**
   * Alters field migrations from file_entity/media in 7 to media in 8.
   *
   * @param array $migrations
   *   The array of migration plugins.
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginException
   *   If a plugin cannot be found.
   */
  protected function alterFieldMigrations(array &$migrations) {
    foreach ($migrations as &$migration) {
      // If this is not a Drupal 7 migration, we can skip processing it.
      if (!in_array('Drupal 7', $migration['migration_tags'] ?? [])) {
        continue;
      }
      $source = NULL;
      if (!empty($migration['source']['plugin'])) {
        $source = MigMagSourceUtility::getSourcePlugin($migration['source']);
        if (is_a($migration['class'], FieldMigration::class, TRUE)) {

          // Field storage, instance, widget and formatter migrations.
          if (is_a($source, Field::class) || is_a($source, FieldInstance::class)) {
            static::mapMigrationProcessValueToMedia($migration, 'entity_type');
          }
        }

        // View Modes.
        if (is_a($source, ViewMode::class)) {
          static::mapMigrationProcessValueToMedia($migration, 'targetEntityType');
        }

        // D7 field instance migrations should have optional dependency on
        // media types — just like it already does for node type, comment type
        // and vocabulary type in core.
        if ($migration['source']['plugin'] === 'd7_field_instance') {
          $migration['migration_dependencies']['optional'][] = 'd7_file_entity_type';
        }
      }
    }
  }

  /**
   * Appends text processors to transform D7 tokens to embeds.
   *
   * Find field instances with text processing and pass them to a
   * MediaWysiwyg plugin that will add processors to the respective
   * migrations.
   *
   * @param array $migrations
   *   The array of migration plugins.
   *
   * @see \Drupal\media_migration\Plugin\MediaWysiwyg\Node
   */
  protected function addMediaWysiwygProcessor(array &$migrations) :void {
    $field_instance_migrations = array_filter($migrations, function (array $definition) {
      return $definition['id'] === 'd7_field_instance';
    });

    if (empty($field_instance_migrations)) {
      return;
    }

    $fields_in_content_entity_migrations_processed = [];
    $source_entity_types_without_plugin = [];

    foreach ($field_instance_migrations as $field_instance_migration_definition) {
      $field_instance_source = MigMagSourceUtility::getSourcePlugin($field_instance_migration_definition['source']);

      if ($field_instance_source instanceof RequirementsInterface) {
        try {
          $field_instance_source->checkRequirements();
        }
        catch (RequirementsException $e) {
          continue;
        }
      }

      foreach ($field_instance_source as $row) {
        assert($row instanceof Row);
        $source_entity_type_id = $row->getSourceProperty('entity_type');

        if (
          !in_array($source_entity_type_id, $source_entity_types_without_plugin, TRUE) &&
          $row->getSourceProperty('field_definition')['module'] === 'text' &&
          $row->getSourceProperty('settings/text_processing') !== 0
        ) {
          $field_name = $row->getSourceProperty('field_name');

          if (
            !empty($fields_in_content_entity_migrations_processed[$source_entity_type_id]) &&
            in_array($field_name, $fields_in_content_entity_migrations_processed[$source_entity_type_id], TRUE)
          ) {
            continue;
          }

          try {
            $plugin = $this->pluginManagerMediaWysiwyg->createInstanceFromSourceEntityType($source_entity_type_id);
            $migrations = $plugin->process($migrations, $row);
          }
          catch (PluginException $e) {
            $source_entity_types_without_plugin[] = $source_entity_type_id;
            $this->logger->warning(
              sprintf(
                "Could not find a MediaWysiwyg plugin for field '%s' used in source entity type '%s'. You probably need to create a new one. Have a look at '%s' for an example.",
                $row->getSourceProperty('field_name'),
                $source_entity_type_id,
                Paragraphs::class
              )
            );
          }

          $fields_in_content_entity_migrations_processed[$source_entity_type_id][] = $field_name;
        }
      }
    }
  }

  /**
   * Maps Drupal 7 media_filter filter plugin to a Drupal 8|9 filter plugin.
   *
   * If Entity Embed module is installed on the destination site, this method
   * maps the media_embed filter plugin (Drupal 7 Media WYSIWYG module) to
   * entity_embed filter plugin (from the Entity Embed module).
   * If Entity Embed is unavailable, the media_filter filter will be mapped to
   * media_embed filter (from core Media Library module).
   *
   * @param array $migrations
   *   The array of migration plugins.
   */
  protected function alterFilterFormatMigration(array &$migrations) :void {
    $destination_filter_plugin_id = MediaMigration::getEmbedTokenDestinationFilterPlugin();
    // If entity_embed is not installed, the destination entity type of the
    // "d7_embed_button_media" migration is missing.
    if (!$this->moduleHandler->moduleExists('entity_embed')) {
      unset($migrations['d7_embed_button_media']);
    }

    if (isset($migrations['d7_filter_format']) && MediaMigration::embedTokenDestinationFilterPluginIsValid($destination_filter_plugin_id)) {
      $migrations['d7_filter_format']['process']['filters']['process']['id']['map']['media_filter'] = $destination_filter_plugin_id;
    }
    else {
      // We don't know the transform type or the filter format migration does
      // not exist.
      return;
    }

    if (MediaMigration::MEDIA_TOKEN_DESTINATION_FILTER_ENTITY_EMBED == $destination_filter_plugin_id && isset($migrations['d7_filter_format']) && isset($migrations['d7_embed_button_media'])) {
      $migrations['d7_filter_format']['migration_dependencies']['required'][] = 'd7_embed_button_media';
    }

    // We have to add <drupal-entity> or <drupal-media> to the allowed html
    // tag's list.
    if (isset($migrations['d7_filter_format'])) {
      $filter_plugin_settings_processes = MigMagMigrationUtility::getAssociativeMigrationProcess($migrations['d7_filter_format']['process']['filters']['process']['settings']);
      $filter_plugin_settings_processes[] = [
        'plugin' => 'filter_settings_embed_media',
      ];
      $migrations['d7_filter_format']['process']['filters']['process']['settings'] = $filter_plugin_settings_processes;
    }
  }

  /**
   * Maps a migration's property from "file" to "media".
   *
   * @param array $migration
   *   The migration to alter.
   * @param string $property
   *   The property to change.
   */
  public static function mapMigrationProcessValueToMedia(array &$migration, string $property) {
    if (!empty($migration['source'][__FUNCTION__])) {
      return;
    }

    try {
      $value = static::getSourceValueOfMigrationProcess($migration, $property);
      switch ($value) {
        case 'file':
          $migration['source']["media_migration_$property"] = 'media';
          $migration['process'][$property] = "media_migration_$property";
          break;

        case NULL:
          // The value of the property cannot be determined, it might be a
          // dynamic value.
          $entity_type_process = MigMagMigrationUtility::getAssociativeMigrationProcess($migration['process'][$property]);
          $entity_type_process[] = [
            'plugin' => 'static_map',
            'map' => [
              'file' => 'media',
            ],
            'bypass' => TRUE,
          ];
          $migration['process'][$property] = $entity_type_process;
          break;
      }
    }
    catch (\LogicException $e) {
      // The process property does not exists, nothing to do.
    }

    $migration['source'][__FUNCTION__] = TRUE;
  }

  /**
   * Gets the value of a process property if it is not dynamically calculated.
   *
   * @param array $migration
   *   The migration plugin's definition array.
   * @param string $process_property_key
   *   The property to check.
   *
   * @return mixed|null
   *   The value of the property if it can be determined, or NULL if it seems
   *   to be dynamic.
   *
   * @throws \LogicException.
   *   When the process property does not exists.
   */
  public static function getSourceValueOfMigrationProcess(array $migration, string $process_property_key) {
    if (
      !array_key_exists('process', $migration) ||
      !is_array($migration['process']) ||
      !array_key_exists($process_property_key, $migration['process'])
    ) {
      throw new \LogicException('No corresponding process found');
    }

    $property_processes = MigMagMigrationUtility::getAssociativeMigrationProcess($migration['process'][$process_property_key]);
    $the_first_process = reset($property_processes);
    $property_value = NULL;

    if (
      !array_key_exists('source', $migration) ||
      count($property_processes) !== 1 ||
      $the_first_process['plugin'] !== 'get' ||
      empty($the_first_process['source'])
    ) {
      return NULL;
    }

    $process_value_source = $the_first_process['source'];

    // Parsing string values like "whatever" or "constants/whatever/key".
    // If the property is set to an already available value (e.g. a constant),
    // we don't need our special mapping applied.
    $property_value = NestedArray::getValue($migration['source'], explode(Row::PROPERTY_SEPARATOR, $process_value_source), $key_exists);

    // Migrations using the "embedded_data" source plugin actually contain
    // rows with source values.
    if (!$key_exists && $migration['source']['plugin'] === 'embedded_data') {
      $embedded_rows = $migration['source']['data_rows'] ?? [];
      $embedded_property_values = array_reduce($embedded_rows, function (array $carry, array $row) use ($process_value_source) {
        $embedded_value = NestedArray::getValue($row, explode(Row::PROPERTY_SEPARATOR, $process_value_source));
        $carry = array_unique(array_merge($carry, [$embedded_value]));
        return $carry;
      }, []);
      return count($embedded_property_values) === 1
        ? $embedded_property_values[0]
        : NULL;
    }

    return $key_exists ? $property_value : NULL;
  }

}

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

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