diff --git a/core/modules/migrate/src/Entity/Migration.php b/core/modules/migrate/src/Entity/Migration.php index 3143b62..8bde52e 100644 --- a/core/modules/migrate/src/Entity/Migration.php +++ b/core/modules/migrate/src/Entity/Migration.php @@ -224,6 +224,16 @@ public function getSourcePlugin() { /** * {@inheritdoc} */ + public function setSourceConfig($source_config) { + $this->source = $source_config; + // Invalidate the source plugin. + unset($this->sourcePlugin); + return $this; + } + + /** + * {@inheritdoc} + */ public function getProcessPlugins(array $process = NULL) { if (!isset($process)) { $process = $this->process; @@ -428,7 +438,6 @@ public function mergeProcessOfProperty($property, array $process_of_property) { else { $this->setProcessOfProperty($property, $process_of_property); } - return $this; } @@ -468,4 +477,5 @@ public function setTrackLastImported($track_last_imported) { public function getMigrationDependencies() { return $this->migration_dependencies; } + } diff --git a/core/modules/migrate/src/Entity/MigrationInterface.php b/core/modules/migrate/src/Entity/MigrationInterface.php index bce1854..1594f93 100644 --- a/core/modules/migrate/src/Entity/MigrationInterface.php +++ b/core/modules/migrate/src/Entity/MigrationInterface.php @@ -108,6 +108,20 @@ public function getSourcePlugin(); /** + * Set the source config for the source plugin. + * + * Warning, you should not use this method unless you have to. This method + * invalidates the source plugin which could cause issues if done during at + * the wrong time. + * + * @param array $source_config + * The new migration source configuration. + * + * @return $this + */ + public function setSourceConfig($source_config); + + /** * Returns the process plugins. * * @param array $process @@ -216,8 +230,6 @@ public function setProcess(array $process); * * @return $this * The migration entity. - * - * @see Drupal\migrate_drupal\Plugin\migrate\load\LoadEntity::processLinkField(). */ public function setProcessOfProperty($property, $process_of_property); diff --git a/core/modules/migrate/src/Plugin/MigratePluginManager.php b/core/modules/migrate/src/Plugin/MigratePluginManager.php index 67cce89..f6eee47 100644 --- a/core/modules/migrate/src/Plugin/MigratePluginManager.php +++ b/core/modules/migrate/src/Plugin/MigratePluginManager.php @@ -46,13 +46,6 @@ class MigratePluginManager extends DefaultPluginManager { * The annotation class name. */ public function __construct($type, \Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, $annotation = 'Drupal\Component\Annotation\PluginID') { - $plugin_interface_map = array( - 'destination' => 'Drupal\migrate\Plugin\MigrateDestinationInterface', - 'process' => 'Drupal\migrate\Plugin\MigrateProcessInterface', - 'source' => 'Drupal\migrate\Plugin\MigrateSourceInterface', - 'id_map' => 'Drupal\migrate\Plugin\MigrateIdMapInterface', - 'entity_field' => 'Drupal\migrate\Plugin\MigrateEntityDestinationFieldInterface', - ); $plugin_interface = isset($plugin_interface_map[$type]) ? $plugin_interface_map[$type] : NULL; parent::__construct("Plugin/migrate/$type", $namespaces, $module_handler, $plugin_interface, $annotation); $this->alterInfo('migrate_' . $type . '_info'); @@ -77,4 +70,20 @@ public function createInstance($plugin_id, array $configuration = array(), Migra return $plugin; } + /** + * Helper for the plugin type to interface map. + * + * @return array + * An array map from plugin type to interface. + */ + protected function getPluginInterfaceMap() { + return [ + 'destination' => 'Drupal\migrate\Plugin\MigrateDestinationInterface', + 'process' => 'Drupal\migrate\Plugin\MigrateProcessInterface', + 'source' => 'Drupal\migrate\Plugin\MigrateSourceInterface', + 'id_map' => 'Drupal\migrate\Plugin\MigrateIdMapInterface', + 'entity_field' => 'Drupal\migrate\Plugin\MigrateEntityDestinationFieldInterface', + ]; + } + } diff --git a/core/modules/migrate_drupal/migrate_drupal.services.yml b/core/modules/migrate_drupal/migrate_drupal.services.yml index 2c8f00c..301ced8 100644 --- a/core/modules/migrate_drupal/migrate_drupal.services.yml +++ b/core/modules/migrate_drupal/migrate_drupal.services.yml @@ -2,3 +2,6 @@ services: plugin.manager.migrate.load: class: Drupal\migrate_drupal\Plugin\MigratePluginManager arguments: [load, '@container.namespaces', '@cache.discovery', '@module_handler'] + plugin.manager.migrate.cckfield: + class: Drupal\migrate_drupal\Plugin\MigratePluginManager + arguments: [cckfield, '@container.namespaces', '@cache.discovery', '@module_handler'] diff --git a/core/modules/migrate_drupal/src/MigrationStorage.php b/core/modules/migrate_drupal/src/MigrationStorage.php index e495122..3585998 100644 --- a/core/modules/migrate_drupal/src/MigrationStorage.php +++ b/core/modules/migrate_drupal/src/MigrationStorage.php @@ -10,6 +10,8 @@ use Drupal\Component\Utility\String; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityStorageException; +use Drupal\migrate_drupal\Plugin\CckFieldMigrateSourceInterface; +use Drupal\migrate\Entity\MigrationInterface; use Drupal\migrate\MigrationStorage as BaseMigrationStorage; /** @@ -18,6 +20,18 @@ class MigrationStorage extends BaseMigrationStorage { /** + * A cached array of cck field plugins. + * + * @var array + */ + protected $cckFieldPlugins; + + /** + * @var \Drupal\migrate_drupal\Plugin\MigratePluginManager + */ + protected $cckPluginManager; + + /** * {@inheritdoc} */ public function loadMultiple(array $ids = NULL) { @@ -84,6 +98,10 @@ public function loadMultiple(array $ids = NULL) { } } + // Allow modules providing cck field plugins to alter the required + // migrations for successfully migration a field type. + $this->applyCckFieldProcessors($entities); + // Build an array of dependencies and set the order of the migrations. return $this->buildDependencyMigration($entities, $dynamic_ids); } @@ -113,4 +131,83 @@ public function save(EntityInterface $entity) { return parent::save($entity); } + /** + * Allow any field type plugins to adjust the migrations as required. + * + * @param array $entities + * An array of migration entities. + */ + protected function applyCckFieldProcessors(array $entities) { + $method_map = $this->getMigrationPluginMethodMap(); + + /** @var \Drupal\migrate\Entity\Migration $migration */ + foreach ($entities as $entity_id => $migration) { + + // Allow field plugins to process the required migrations. + if (isset($method_map[$entity_id])) { + $method = $method_map[$entity_id]; + $cck_plugins = $this->getCckFieldPlugins(); + + array_walk($cck_plugins, function ($plugin) use ($method, $migration) { + $plugin->$method($migration); + }); + } + + // If this is a CCK bundle migration, allow the cck field plugins to add + // any field type processing. + $source_plugin = $migration->getSourcePlugin(); + if ($source_plugin instanceof CckFieldMigrateSourceInterface && $source_plugin->getDerivativeId()) { + $plugins = $this->getCckFieldPlugins(); + foreach ($source_plugin->fieldData() as $field_name => $data) { + if (isset($plugins[$data['type']])) { + $plugins[$data['type']]->processCckFieldValues($migration, $field_name, $data); + } + } + } + } + } + + /** + * Get an array of loaded cck field plugins. + * + * @return \Drupal\migrate_drupal\Plugin\MigrateCckFieldInterface[] + * An array of cck field process plugins. + */ + protected function getCckFieldPlugins() { + if (!isset($this->cckFieldPlugins)) { + $this->cckFieldPlugins = []; + foreach ($this->getCckPluginManager()->getDefinitions() as $definition) { + $this->cckFieldPlugins[$definition['id']] = $this->getCckPluginManager()->createInstance($definition['id']); + } + } + return $this->cckFieldPlugins; + } + + /** + * Provides a map between migration ids and the cck field plugin method. + * + * @return array + * The map between migrations and cck field plugin processing methods. + */ + protected function getMigrationPluginMethodMap() { + return [ + 'd6_field' => 'processField', + 'd6_field_instance_widget_settings' => 'processFieldWidget', + 'd6_field_formatter_settings' => 'processFieldDisplay', + ]; + } + + /** + * Get the cck field plugin manager. + * + * @return \Drupal\migrate_drupal\Plugin\MigratePluginManager + * The loaded plugin manager. + */ + protected function getCckPluginManager() { + if (!isset($this->cckPluginManager)) { + $this->cckPluginManager = \Drupal::service('plugin.manager.migrate.cckfield'); + } + return $this->cckPluginManager; + } + } diff --git a/core/modules/migrate_drupal/src/Plugin/MigrateCckFieldInterface.php b/core/modules/migrate_drupal/src/Plugin/MigrateCckFieldInterface.php new file mode 100644 index 0000000..2cb59a7 --- /dev/null +++ b/core/modules/migrate_drupal/src/Plugin/MigrateCckFieldInterface.php @@ -0,0 +1,60 @@ +factory = new ContainerFactory($this, 'Drupal\migrate_drupal\Plugin\MigrateLoadInterface'); + protected function getPluginInterfaceMap() { + return parent::getPluginInterfaceMap() + [ + 'load' => 'Drupal\migrate_drupal\Plugin\MigrateLoadInterface', + 'cckfield' => 'Drupal\migrate_drupal\Plugin\MigrateCckFieldInterface', + ]; } - } diff --git a/core/modules/migrate_drupal/src/Plugin/migrate/cckfield/CckFieldPluginBase.php b/core/modules/migrate_drupal/src/Plugin/migrate/cckfield/CckFieldPluginBase.php new file mode 100644 index 0000000..561b761 --- /dev/null +++ b/core/modules/migrate_drupal/src/Plugin/migrate/cckfield/CckFieldPluginBase.php @@ -0,0 +1,53 @@ +pluginId][$this->pluginId] = $this->pluginId; + $migration->mergeProcessOfProperty('type', $process); + } + + /** + * {@inheritdoc} + */ + public function processFieldWidget(MigrationInterface $migration) { + $process['type']['map'][$this->pluginId] = $this->pluginId . '_default'; + $migration->mergeProcessOfProperty('options/type', $process); + } + + /** + * {@inheritdoc} + */ + public function processFieldDisplay(MigrationInterface $migration) { + $process = []; + foreach ($this->getFieldDisplayMap() as $source_format => $destination_format) { + $process[0]['map'][$this->pluginId][$source_format] = $destination_format; + } + $migration->mergeProcessOfProperty('options/type', $process); + } + +} diff --git a/core/modules/migrate_drupal/src/Tests/d6/MigrateFileTest.php b/core/modules/migrate_drupal/src/Tests/d6/MigrateFileTest.php index 4adbcb2..78ae03b 100644 --- a/core/modules/migrate_drupal/src/Tests/d6/MigrateFileTest.php +++ b/core/modules/migrate_drupal/src/Tests/d6/MigrateFileTest.php @@ -36,11 +36,12 @@ protected function setUp() { $dumps = array( $this->getDumpDirectory() . '/Files.php', ); + /** @var \Drupal\migrate\Entity\MigrationInterface $migration */ $migration = entity_load('migration', 'd6_file'); - $source = $migration->get('source'); - $source['conf_path'] = 'core/modules/simpletest'; - $migration->set('source', $source); + $source = $migration->get('source') + ['conf_path' => 'core/modules/simpletest']; + $migration->setSourceConfig($source); + $this->prepare($migration, $dumps); $executable = new MigrateExecutable($migration, $this); $executable->import(); diff --git a/core/modules/migrate_drupal/src/Tests/d6/MigrateUserPictureFileTest.php b/core/modules/migrate_drupal/src/Tests/d6/MigrateUserPictureFileTest.php index be028c0..9226314 100644 --- a/core/modules/migrate_drupal/src/Tests/d6/MigrateUserPictureFileTest.php +++ b/core/modules/migrate_drupal/src/Tests/d6/MigrateUserPictureFileTest.php @@ -37,9 +37,9 @@ protected function setUp() { ); /** @var \Drupal\migrate\Entity\MigrationInterface $migration */ $migration = entity_load('migration', 'd6_user_picture_file'); - $source = $migration->get('source'); - $source['conf_path'] = 'core/modules/simpletest'; - $migration->set('source', $source); + $source = $migration->get('source') + ['conf_path' => 'core/modules/simpletest']; + $migration->setSourceConfig($source); + $this->prepare($migration, $dumps); $executable = new MigrateExecutable($migration, $this); $executable->import();