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..84aa06a --- /dev/null +++ b/migrations/d7_profile2_type.yml @@ -0,0 +1,25 @@ +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 0143b7a..7b8aed7 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(). @@ -293,3 +297,85 @@ function profile_entity_base_field_info(EntityTypeInterface $entity_type) { return $fields; } } + +/** + * Implements hook_migration_plugins_alter(). + */ +function profile_migration_plugins_alter(array &$migrations) { + /** @var \Drupal\migrate\Plugin\MigrationPluginManager $migration_plugin_manager */ + $migration_plugin_manager = \Drupal::service('plugin.manager.migration'); + /** @var \Drupal\migrate\Plugin\MigrateSourcePluginManager $source_plugin_manager */ + $source_plugin_manager = \Drupal::service('plugin.manager.migrate.source'); + + foreach ($migrations as $key => &$migration) { + $migration_stub = $migration_plugin_manager->createStubMigration($migration); + $configuration = $migration['source']; + $source = $source_plugin_manager->createInstance($migration['source']['plugin'], $configuration, $migration_stub); + + foreach (['entity_type', 'targetEntityType'] as $entity_type) { + if (isset($migration['process'][$entity_type])) { + _profile_migration_entity_type_adjust($migration, $entity_type); + $migration['migration_dependencies']['optional']['d7_profile2_type'] = 'd7_profile2_type'; + } + } + } +} + +/** + * 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, string $destination) { + if (!_profile_migration_prepare_process($migration['process'], $destination)) { + return; + } + + $entity_type_process = &$migration['process'][$destination]; + $entity_type_process['profile'] = [ + 'plugin' => 'static_map', + 'map' => [ + 'profile2' => 'profile', + ], + 'bypass' => TRUE, + ]; +} + +/** + * Prepare process array for adding another process elements. + * + * @param mixed $process + * + * @return bool Is success. + * + * @throws \Exception + */ +function _profile_migration_prepare_process(&$process, string $index): bool { + if (!isset($process[$index])) { + return FALSE; + } + + $p = &$process[$index]; + + // Try to play with other modules altering this, and don't replace it + // outright unless it's unchanged. + if (is_string($p)) { + $p = [ + [ + 'plugin' => 'get', + 'source' => $p, + ], + ]; + } + elseif (isset($p['plugin'])) { + $p = [$p]; + } + elseif (!is_array($p)) { + throw new \Exception(sprintf('Unknown process element type: %s.', print_r($p, TRUE))); + } + + return TRUE; +} diff --git a/src/Plugin/migrate/D7Profile2Deriver.php b/src/Plugin/migrate/D7Profile2Deriver.php new file mode 100644 index 0000000..70695c6 --- /dev/null +++ b/src/Plugin/migrate/D7Profile2Deriver.php @@ -0,0 +1,102 @@ +basePluginId = $base_plugin_id; + $this->fieldDiscovery = $field_discovery; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, $base_plugin_id) { + return new static( + $base_plugin_id, + $container->get('migrate_drupal.field_discovery') + ); + } + + /** + * {@inheritdoc} + */ + public function getDerivativeDefinitions($base_plugin_definition) { + $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'] = $this->t('@label (@type)', [ + '@label' => $values['label'], + '@type' => $row->getSourceProperty('name'), + ]); + $values['source']['bundle'] = $bundle; + $values['destination']['default_bundle'] = $bundle; + + /** @var \Drupal\migrate\Plugin\Migration $migration */ + $migration = \Drupal::service('plugin.manager.migration')->createStubMigration($values); + $this->fieldDiscovery->addBundleFieldProcesses($migration, 'profile2', $bundle); + $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..a697be5 --- /dev/null +++ b/src/Plugin/migrate/source/d7/Profile2.php @@ -0,0 +1,72 @@ +select('profile', 'p') + ->fields('p') + ->distinct() + ->orderBy('pid'); + // Skip profiles with invalid users. + $query->innerJoin('users', 'u', 'p.uid = u.uid'); + + 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..16a74d1 --- /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', array_filter($data['roles'])); + } + + return parent::prepareRow($row); + } + + /** + * {@inheritdoc} + */ + public function getIds() { + $ids['id']['type'] = 'integer'; + return $ids; + } + +}