diff --git a/migrations/d7_profile2.yml b/migrations/d7_profile2.yml new file mode 100644 index 0000000..90c5d92 --- /dev/null +++ b/migrations/d7_profile2.yml @@ -0,0 +1,27 @@ +id: d7_profile2 +label: Profile2 +audit: true +migration_tags: + - Drupal 7 + - Content +deriver: Drupal\profile\Plugin\migrate\D7Profile2Deriver +source: + plugin: d7_profile2 + constants: + status: 1 + is_default: 1 +process: + profile_id: pid + type: type + uid: uid + status: 'constants/status' + is_default: 'constants/is_default' + created: created + changed: changed +destination: + plugin: entity:profile +migration_dependencies: + required: + - d7_profile2_type + optional: + - d7_field_instance diff --git a/migrations/d7_profile2_type.yml b/migrations/d7_profile2_type.yml new file mode 100644 index 0000000..d1d5428 --- /dev/null +++ b/migrations/d7_profile2_type.yml @@ -0,0 +1,26 @@ +id: d7_profile2_type +label: Profile2 type +migration_tags: + - Drupal 7 + - Configuration +source: + plugin: d7_profile2_type + constants: + description: 'Migrated from Profile2' + multiple: false + use_revisions: false +process: + id: type + label: label + registration: registration + multiple: 'constants/multiple' + roles: + plugin: migration_lookup + migration: d7_user_role + source: roles + weight: weight + use_revisions: 'constants/use_revisions' + description: 'constants/description' +destination: + plugin: entity:profile_type + diff --git a/profile.module b/profile.module index 132b31e..dce0115 100644 --- a/profile.module +++ b/profile.module @@ -20,6 +20,10 @@ use Drupal\field\FieldConfigInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Url; +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\migrate_drupal\Plugin\migrate\FieldMigration; /** * Implements hook_help(). @@ -384,3 +388,70 @@ function profile_theme_suggestions_profile(array $variables) { return $suggestions; } + +/** + * Implements hook_migration_plugins_alter(). + */ +function profile_migration_plugins_alter(array &$migrations) { + foreach ($migrations as $key => &$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. + if (is_a($source, Field::class)) { + _profile_migration_entity_type_adjust($migration); + } + + // Field instance. + if (is_a($source, FieldInstance::class)) { + _profile_migration_entity_type_adjust($migration); + $migration['migration_dependencies']['optional']['d7_profile2_type'] = 'd7_profile2_type'; + } + } + + // View Modes. + if (is_a($source, ViewMode::class)) { + _profile_migration_entity_type_adjust($migration, 'targetEntityType'); + } + } + } +} + +/** + * Map profile2 fields to 'profile'. + * + * @param array $migration + * Thei migration to process. + * @param string $destination + * The process destination. + */ +function _profile_migration_entity_type_adjust(array &$migration, $destination = 'entity_type') { + $entity_type_process = $migration['process'][$destination]; + + // Try to play with other modules altering this, and don't replace it + // outright unless it's unchanged. + if (!is_array($entity_type_process)) { + $entity_type_process = [ + [ + 'plugin' => 'get', + 'source' => 'entity_type', + ], + ]; + } + $entity_type_process['profile'] = [ + 'plugin' => 'static_map', + 'map' => [ + 'profile2' => 'profile', + ], + 'bypass' => TRUE, + ]; + $migration['process'][$destination] = $entity_type_process; +} diff --git a/src/Plugin/migrate/D7Profile2Deriver.php b/src/Plugin/migrate/D7Profile2Deriver.php new file mode 100644 index 0000000..535c6a8 --- /dev/null +++ b/src/Plugin/migrate/D7Profile2Deriver.php @@ -0,0 +1,170 @@ +basePluginId = $base_plugin_id; + $this->cckPluginManager = $cck_manager; + $this->fieldPluginManager = $field_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, $base_plugin_id) { + return new static( + $base_plugin_id, + $container->get('plugin.manager.migrate.cckfield'), + $container->get('plugin.manager.migrate.field') + ); + } + + /** + * {@inheritdoc} + */ + public function getDerivativeDefinitions($base_plugin_definition) { + $fields = []; + try { + $source_plugin = static::getSourcePlugin('d7_field_instance'); + $source_plugin->checkRequirements(); + + // Read all field instance definitions in the source database. + foreach ($source_plugin as $row) { + if ($row->getSourceProperty('entity_type') == 'profile2') { + $fields[$row->getSourceProperty('bundle')][$row->getSourceProperty('field_name')] = $row->getSource(); + } + } + } + catch (RequirementsException $e) { + // If checkRequirements() failed then the field module did not exist and + // we do not have any fields. Therefore, $fields will be empty and below + // we'll create a migration just for the node properties. + } + + $type_source_plugin = static::getSourcePlugin('d7_profile2_type'); + try { + $type_source_plugin->checkRequirements(); + } + catch (RequirementsException $e) { + // If the d7_profile2_type requirements failed, that means we do not + // have a Drupal source database configured - there is nothing to + // generate. + return $this->derivatives; + } + + try { + foreach ($type_source_plugin as $row) { + $bundle = $row->getSourceProperty('type'); + $values = $base_plugin_definition; + + $values['label'] = t('@label (@type)', [ + '@label' => $values['label'], + '@type' => $row->getSourceProperty('name'), + ]); + $values['source']['bundle'] = $bundle; + $values['destination']['default_bundle'] = $bundle; + + /** @var Migration $migration */ + $migration = \Drupal::service('plugin.manager.migration')->createStubMigration($values); + if (isset($fields[$bundle])) { + foreach ($fields[$bundle] 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] + ->processFieldValues($migration, $field_name, $info); + } + catch (PluginNotFoundException $ex) { + try { + $plugin_id = $this->cckPluginManager->getPluginIdFromFieldType($field_type, ['core' => 7], $migration); + if (!isset($this->cckPluginCache[$field_type])) { + $this->cckPluginCache[$field_type] = $this->cckPluginManager->createInstance($plugin_id, ['core' => 7], $migration); + } + $this->cckPluginCache[$field_type] + ->processCckFieldValues($migration, $field_name, $info); + } + catch (PluginNotFoundException $ex) { + $migration->setProcessOfProperty($field_name, $field_name); + } + } + } + } + $this->derivatives[$bundle] = $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/src/Plugin/migrate/source/d7/Profile2.php b/src/Plugin/migrate/source/d7/Profile2.php new file mode 100644 index 0000000..cbfadff --- /dev/null +++ b/src/Plugin/migrate/source/d7/Profile2.php @@ -0,0 +1,70 @@ +select('profile', 'p') + ->fields('p') + ->distinct() + ->orderBy('pid'); + + if (isset($this->configuration['bundle'])) { + $query->condition('p.type', (array) $this->configuration['bundle'], 'IN'); + } + + return $query; + } + + /** + * {@inheritdoc} + */ + public function fields() { + $fields = [ + 'pid' => $this->t('Primary Key: Unique profile item ID.'), + 'type' => $this->t('The {profile_type}.type of this profile.'), + 'uid' => $this->t('The {users}.uid of the associated user.'), + 'label' => $this->t('A human-readable label for this profile.'), + 'created' => $this->t('The Unix timestamp when the profile was created.'), + 'changed' => $this->t("The Unix timestamp when the profile was most recently saved."), + ]; + return $fields; + } + + /** + * {@inheritdoc} + */ + public function prepareRow(Row $row) { + // Get Field API field values. + foreach (array_keys($this->getFields('profile2', $row->getSourceProperty('type'))) as $field) { + $tid = $row->getSourceProperty('pid'); + $row->setSourceProperty($field, $this->getFieldValues('profile2', $field, $tid)); + } + + return parent::prepareRow($row); + } + + /** + * {@inheritdoc} + */ + public function getIds() { + $ids['pid']['type'] = 'integer'; + return $ids; + } + +} diff --git a/src/Plugin/migrate/source/d7/Profile2Type.php b/src/Plugin/migrate/source/d7/Profile2Type.php new file mode 100644 index 0000000..85dec94 --- /dev/null +++ b/src/Plugin/migrate/source/d7/Profile2Type.php @@ -0,0 +1,74 @@ +select('profile_type', 'pt') + ->fields('pt', [ + 'id', + 'type', + 'label', + 'weight', + 'data', + 'status', + 'module', + ]); + return $query; + } + + /** + * {@inheritdoc} + */ + public function fields() { + return [ + 'id' => $this->t('Primary Key: Unique profile type ID.'), + 'type' => $this->t('The machine-readable name of this profile type.'), + 'label' => $this->t('The human-readable name of this profile type.'), + 'weight' => $this->t('The weight of this profile type in relation to others.'), + 'data' => $this->t('A serialized array of additional data related to this profile type.'), + 'status' => $this->t('The exportable status of the entity.'), + 'module' => $this->t('The name of the providing module if the entity has been defined in code.'), + ]; + } + + /** + * {@inheritdoc} + */ + public function prepareRow(Row $row) { + $data = unserialize($row->getSourceProperty('data')); + + $row->setSourceProperty('registration', $data['registration']); + $row->setSourceProperty('use_page', $data['use_page']); + + if (isset($data['roles'])) { + $row->setSourceProperty('roles', $data['roles']); + } + + return parent::prepareRow($row); + } + + /** + * {@inheritdoc} + */ + public function getIds() { + $ids['id']['type'] = 'integer'; + return $ids; + } + +}