diff --git a/core/modules/media/media.module b/core/modules/media/media.module index 8c90b3bfff..660f326cc9 100644 --- a/core/modules/media/media.module +++ b/core/modules/media/media.module @@ -16,7 +16,14 @@ use Drupal\Core\Template\Attribute; use Drupal\Core\Url; use Drupal\field\FieldConfigInterface; +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\Plugin\media\Source\OEmbedInterface; +use Drupal\migrate\Plugin\MigrateSourceInterface; +use Drupal\migrate\Plugin\MigrationInterface; +use Drupal\migrate\Row; +use Drupal\migrate_drupal\Plugin\migrate\FieldMigration; use Drupal\views\ViewExecutable; /** @@ -358,6 +365,120 @@ function _media_get_add_url($allowed_bundles) { return FALSE; } +/** + * Implements hook_migration_plugins_alter(). + */ +function media_migration_plugins_alter(array &$migrations) { + foreach ($migrations as &$migration) { + /** @var \Drupal\migrate\Plugin\MigrationPluginManager $migration_plugin_manager */ + $migration_plugin_manager = \Drupal::service('plugin.manager.migration'); + $migration_stub = $migration_plugin_manager->createStubMigration($migration); + /** @var \Drupal\migrate\Plugin\MigrateSourcePluginManager $source_plugin_manager */ + $source_plugin_manager = \Drupal::service('plugin.manager.migrate.source'); + $source = NULL; + $configuration = $migration['source']; + $source = $source_plugin_manager->createInstance($migration['source']['plugin'], $configuration, $migration_stub); + if ($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)) { + _media_map_file_to_media_bundle($migration, 'entity_type'); + } + } + + // View Modes. + if (is_a($source, ViewMode::class)) { + _media_map_file_to_media_bundle($migration, 'targetEntityType'); + } + } + } + +} + +/** + * Adds static mapping from file to media to a migrate process. + * + * @param array $migration + * The migration to alter. + * @param string $mapping_source + * The process mapping identifier. + */ +function _media_map_file_to_media_bundle(array &$migration, $mapping_source) { + $entity_type_process = $migration['process'][$mapping_source]; + + if (isset($entity_type_process['file_entity'])) { + return; + } + $entity_type_process = _media_make_associative($entity_type_process); + + $entity_type_process['file_entity'] = [ + 'plugin' => 'static_map', + 'map' => [ + 'file' => 'media', + ], + 'bypass' => TRUE, + ]; + $migration['process'][$mapping_source] = $entity_type_process; +} + +/** + * Ensures that a plugin process mapping is an associative array. + * + * @param array|string $plugin_process + * The plugin process mapping. + * + * @return array + * The plugin process mapping as an associative array. + */ +function _media_make_associative($plugin_process) { + if (!is_array($plugin_process)) { + $plugin_process = [ + [ + 'plugin' => 'get', + 'source' => $plugin_process, + ], + ]; + } + elseif (array_key_exists('plugin', $plugin_process)) { + $plugin_process = [$plugin_process]; + } + + return $plugin_process; +} + +/** + * Implements hook_migrate_prepare_row(). + */ +function media_migrate_prepare_row(Row $row, MigrateSourceInterface $source, MigrationInterface $migration) { + // Change the type from file to file_entity for fields that use the Media + // Generic widget so they can be transformed into entity reference media + // fields. + // + // @see \Drupal\file_entity_migration\Plugin\migrate\field\FileEntity + if (('d7_field' == $source->getPluginId()) && + ($row->getSourceProperty('type') == 'file')) { + foreach ($row->getSourceProperty('instances') as $instance) { + $data = unserialize($instance['data']); + if ($data['widget']['type'] == 'media_generic') { + $row->setSourceProperty('type', 'file_entity'); + } + } + } + + if (in_array($migration->getSourcePlugin()->getPluginId(), [ + 'd7_field_instance', + 'd7_field_instance_per_view_mode', + 'd7_view_mode', + ])) { + if (($row->getSourceProperty('type') == 'file') && + ($row->getSourceProperty('widget')['type'] == 'media_generic')) { + + $row->setSourceProperty('type', 'file_entity'); + } + } +} + /** * Implements hook_entity_type_alter(). */ diff --git a/core/modules/media/migrations/d7_file_entity.yml b/core/modules/media/migrations/d7_file_entity.yml new file mode 100644 index 0000000000..5b5628821f --- /dev/null +++ b/core/modules/media/migrations/d7_file_entity.yml @@ -0,0 +1,18 @@ +id: d7_file_entity +label: File Entity migration +audit: true +migration_tags: + - Drupal 7 + - Content +deriver: Drupal\media\Plugin\migrate\D7FileEntityItemDeriver +source: + plugin: d7_file_entity_item +process: + mid: fid + bundle: type +destination: + plugin: entity:media +migration_dependencies: + optional: + - d7_file_entity_type + - d7_field_instance diff --git a/core/modules/media/migrations/d7_file_entity_type.yml b/core/modules/media/migrations/d7_file_entity_type.yml new file mode 100644 index 0000000000..23146319b2 --- /dev/null +++ b/core/modules/media/migrations/d7_file_entity_type.yml @@ -0,0 +1,15 @@ +id: d7_file_entity_type +label: File Entity to Media Bundle migration +migration_tags: + - Drupal 7 + - Configuration +source: + plugin: d7_file_entity_type + constants: + status: true +process: + id: type + label: type + status: constants/status +destination: + plugin: 'entity:media_type' diff --git a/core/modules/media/src/Plugin/migrate/D7FileEntityItemDeriver.php b/core/modules/media/src/Plugin/migrate/D7FileEntityItemDeriver.php new file mode 100644 index 0000000000..77bdec6f34 --- /dev/null +++ b/core/modules/media/src/Plugin/migrate/D7FileEntityItemDeriver.php @@ -0,0 +1,175 @@ +basePluginId = $base_plugin_id; + $this->fieldPluginManager = $field_manager; + $this->entityTypeManager = $entity_type_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, $base_plugin_id) { + return new static( + $base_plugin_id, + $container->get('plugin.manager.migrate.field'), + $container->get('entity_type.manager') + ); + } + + /** + * {@inheritdoc} + */ + public function getDerivativeDefinitions($base_plugin_definition) { + $types = static::getSourcePlugin('d7_file_entity_type'); + + try { + $types->checkRequirements(); + } + catch (RequirementsException $e) { + return $this->derivatives; + } + + $fields = []; + try { + $source_plugin = static::getSourcePlugin('d7_field_instance'); + $source_plugin->checkRequirements(); + + foreach ($source_plugin as $row) { + if ($row->getSourceProperty('entity_type') == 'file') { + $fields[$row->getSourceProperty('bundle')][$row->getSourceProperty('field_name')] = $row->getSource(); + } + } + } + catch (RequirementsException $e) { + // No fields, no problem. We can keep going. + } + + try { + foreach ($types as $row) { + /** @var \Drupal\migrate\Row $row */ + $values = $base_plugin_definition; + $bundle_name = $row->getSourceProperty('type'); + + // Check that there is a corresponding media bundle. + /** @var \Drupal\media\MediaTypeInterface $media_type */ + $media_type = $this->entityTypeManager->getStorage('media_type') + ->load($bundle_name); + if (empty($media_type)) { + continue; + } + + // Create the migration derivative. + $values['source']['type'] = $bundle_name; + $values['label'] = t('@label (@type)', [ + '@label' => $base_plugin_definition['label'], + '@type' => $bundle_name, + ]); + $values['destination']['bundle'] = $bundle_name; + $values['process'][$media_type->getSource()->getConfiguration()['source_field'] . '/target_id'] = 'fid'; + + /** @var \Drupal\migrate\Plugin\Migration $migration */ + $migration = \Drupal::service('plugin.manager.migration') + ->createStubMigration($values); + if (isset($fields[$bundle_name])) { + foreach ($fields[$bundle_name] as $field_name => $info) { + $field_type = $info['type']; + try { + $plugin_id = $this->fieldPluginManager->getPluginIdFromFieldType($field_type, ['core' => 7], $migration); + if (!isset($this->fieldPluginCache[$field_type])) { + $this->fieldPluginCache[$field_type] = $this->fieldPluginManager->createInstance($plugin_id, ['core' => 7], $migration); + } + $this->fieldPluginCache[$field_type] + ->defineValueProcessPipeline($migration, $field_name, $info); + } + catch (PluginNotFoundException $ex) { + try { + $plugin_id = $this->fieldPluginManager->getPluginIdFromFieldType($field_type, ['core' => 7], $migration); + if (!isset($this->cckPluginCache[$field_type])) { + $this->cckPluginCache[$field_type] = $this->fieldPluginManager->createInstance($plugin_id, ['core' => 7], $migration); + } + $this->cckPluginCache[$field_type] + ->defineValueProcessPipeline($migration, $field_name, $info); + } + catch (PluginNotFoundException $ex) { + $migration->setProcessOfProperty($field_name, $field_name); + } + } + } + } + $this->derivatives[$bundle_name] = $migration->getPluginDefinition(); + } + } + catch (DatabaseExceptionWrapper $e) { + // Once we begin iterating the source plugin it is possible that the + // source tables will not exist. This can happen when the + // MigrationPluginManager gathers up the migration definitions but we do + // not actually have a Drupal 7 source database. + } + return $this->derivatives; + } + +} diff --git a/core/modules/media/src/Plugin/migrate/field/FileEntity.php b/core/modules/media/src/Plugin/migrate/field/FileEntity.php new file mode 100644 index 0000000000..9fa0d8f9fe --- /dev/null +++ b/core/modules/media/src/Plugin/migrate/field/FileEntity.php @@ -0,0 +1,89 @@ + [ + 'plugin' => 'file_entity_field_settings', + ], + ]; + $migration->mergeProcessOfProperty('settings', $settings); + parent::alterFieldMigration($migration); + } + + /** + * {@inheritdoc} + */ + public function alterFieldInstanceMigration(MigrationInterface $migration) { + $settings = [ + 'file_entity' => [ + 'plugin' => 'file_entity_field_instance_settings', + ], + ]; + $migration->mergeProcessOfProperty('settings', $settings); + parent::alterFieldInstanceMigration($migration); + } + + /** + * {@inheritdoc} + */ + public function defineValueProcessPipeline(MigrationInterface $migration, $field_name, $data) { + $process = [ + 'plugin' => 'sub_process', + 'source' => $field_name, + 'process' => [ + 'target_id' => 'fid', + ], + ]; + + $migration->setProcessOfProperty($field_name, $process); + } + + /** + * {@inheritdoc} + */ + public function alterFieldFormatterMigration(MigrationInterface $migration) { + $settings = [ + 'file_entity' => [ + 'plugin' => 'file_entity_field_formatter_settings', + ], + ]; + $migration->setProcessOfProperty('options/settings', $settings); + + parent::alterFieldFormatterMigration($migration); + } + + /** + * {@inheritdoc} + */ + public function getFieldFormatterMap() { + return [ + 'file_image_picture' => 'media_responsive_thumbnail', + 'file_image_image' => 'media_thumbnail', + 'file_rendered' => 'entity_reference_entity_view', + ] + parent::getFieldFormatterMap(); + } + +} diff --git a/core/modules/media/src/Plugin/migrate/process/FileEntityFieldFormatterSettings.php b/core/modules/media/src/Plugin/migrate/process/FileEntityFieldFormatterSettings.php new file mode 100644 index 0000000000..7ca450ecbb --- /dev/null +++ b/core/modules/media/src/Plugin/migrate/process/FileEntityFieldFormatterSettings.php @@ -0,0 +1,44 @@ +getSourceProperty('type')) { + $formatter = $row->getSourceProperty('formatter'); + if (empty($formatter['settings'])) { + $value = []; + } + elseif ('file_image_picture' == $formatter['type']) { + $value['image_link'] = $formatter['settings']['image_link']; + $value['responsive_image_style'] = $formatter['settings']['picture_mapping']; + } + elseif ('file_image_image' == $formatter['type']) { + $value['image_link'] = $formatter['settings']['image_link']; + $value['image_style'] = $formatter['settings']['image_style']; + } + elseif ('file_rendered' == $formatter['type']) { + $value['view_mode'] = $formatter['settings']['file_view_mode']; + $value['link'] = FALSE; + } + } + return $value; + } + +} diff --git a/core/modules/media/src/Plugin/migrate/process/FileEntityFieldInstanceSettings.php b/core/modules/media/src/Plugin/migrate/process/FileEntityFieldInstanceSettings.php new file mode 100644 index 0000000000..396060642f --- /dev/null +++ b/core/modules/media/src/Plugin/migrate/process/FileEntityFieldInstanceSettings.php @@ -0,0 +1,36 @@ +getSourceProperty('type'); + + if ($type == 'file_entity') { + $widget_settings = $row->getSourceProperty('widget'); + if (empty($widget_settings['settings']['allowed_types'])) { + throw new MigrateSkipRowException('No target media bundle found for file_entity field ' . $row->getSourceProperty('field_name')); + } + $target_bundles = array_filter($widget_settings['settings']['allowed_types']); + $value['handler_settings']['target_bundles'] = $target_bundles; + } + return $value; + } + +} diff --git a/core/modules/media/src/Plugin/migrate/process/FileEntityFieldSettings.php b/core/modules/media/src/Plugin/migrate/process/FileEntityFieldSettings.php new file mode 100644 index 0000000000..1b856c8249 --- /dev/null +++ b/core/modules/media/src/Plugin/migrate/process/FileEntityFieldSettings.php @@ -0,0 +1,28 @@ +getSourceProperty('type') == 'file_entity') { + $value['target_type'] = 'media'; + } + return $value; + } + +} diff --git a/core/modules/media/src/Plugin/migrate/source/d7/FileEntityItem.php b/core/modules/media/src/Plugin/migrate/source/d7/FileEntityItem.php new file mode 100644 index 0000000000..d67e0d175b --- /dev/null +++ b/core/modules/media/src/Plugin/migrate/source/d7/FileEntityItem.php @@ -0,0 +1,83 @@ +select('file_managed', 'f') + ->fields('f') + ->orderBy('f.timestamp'); + + // Filter by type, if configured. + if (isset($this->configuration['type'])) { + $query->condition('type', $this->configuration['type']); + } + + return $query; + } + + /** + * {@inheritdoc} + */ + public function prepareRow(Row $row) { + // Get Field API field values. + foreach (array_keys($this->getFields('file', $row->getSourceProperty('type'))) as $field) { + $fid = $row->getSourceProperty('fid'); + $row->setSourceProperty($field, $this->getFieldValues('file', $field, $fid)); + } + + return parent::prepareRow($row); + } + + /** + * {@inheritdoc} + */ + public function fields() { + $fields = [ + 'fid' => $this->t('The file identifier'), + 'uid' => $this->t('The user identifier'), + 'filename' => $this->t('The file name'), + 'uri' => $this->t('The URI of the file'), + 'filemime' => $this->t('The file mimetype'), + 'filesize' => $this->t('The file size'), + 'status' => $this->t('The file status'), + 'timestamp' => $this->t('The time that the file was added'), + 'type' => $this->t('The file type'), + 'created' => $this->t('The created timestamp'), + 'published' => $this->t('The published timestamp'), + 'promote' => $this->t('The promoted flag'), + 'sticky' => $this->t('The sticky flag'), + 'vid' => $this->t('The vid'), + ]; + + return $fields; + } + + /** + * {@inheritdoc} + */ + public function getIds() { + $ids['fid']['type'] = 'integer'; + return $ids; + } + +} diff --git a/core/modules/media/src/Plugin/migrate/source/d7/FileEntityType.php b/core/modules/media/src/Plugin/migrate/source/d7/FileEntityType.php new file mode 100644 index 0000000000..be4dd57096 --- /dev/null +++ b/core/modules/media/src/Plugin/migrate/source/d7/FileEntityType.php @@ -0,0 +1,45 @@ +select('file_managed', 'fm') + ->distinct() + ->fields('fm', ['type']) + ->condition('fm.status', TRUE); + return $query; + } + + /** + * {@inheritdoc} + */ + public function fields() { + return [ + 'type' => $this->t('File Entity type machine name'), + ]; + } + + /** + * {@inheritdoc} + */ + public function getIds() { + $ids['type']['type'] = 'string'; + return $ids; + } + +} diff --git a/core/modules/migrate/tests/src/Kernel/Plugin/MigrationProvidersExistTest.php b/core/modules/migrate/tests/src/Kernel/Plugin/MigrationProvidersExistTest.php index 4a65d82e0f..cdd14f7dba 100644 --- a/core/modules/migrate/tests/src/Kernel/Plugin/MigrationProvidersExistTest.php +++ b/core/modules/migrate/tests/src/Kernel/Plugin/MigrationProvidersExistTest.php @@ -148,6 +148,10 @@ public function testFieldProvidersExist() { 'source_module' => 'user_reference', 'destination_module' => 'core', ], + 'file_entity' => [ + 'source_module' => 'file', + 'destination_module' => 'core', + ], ]; $this->enableAllModules();