diff --git a/metatag.module b/metatag.module index da1d1bf..3bf94cb 100644 --- a/metatag.module +++ b/metatag.module @@ -5,12 +5,19 @@ * Contains metatag.module. */ +use Drupal\Component\Plugin\Factory\DefaultFactory; +use Drupal\Core\Database\Query\SelectInterface; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Url; +use Drupal\migrate\Plugin\migrate\destination\EntityContentBase; +use Drupal\migrate\Plugin\migrate\source\SqlBase; +use Drupal\migrate\Plugin\MigrateSourceInterface; +use Drupal\migrate\Plugin\MigrationInterface; +use Drupal\migrate\Row; /** * Implements hook_help(). @@ -308,3 +315,81 @@ function metatag_get_default_tags() { return $metatags->get('tags'); } + +/** + * Implement hook_migrate_prepare_row(). + * + * @param Row $row + * @param MigrateSourceInterface $source + * @param MigrationInterface $migration + */ +function metatag_migrate_prepare_row(Row $row, MigrateSourceInterface $source, MigrationInterface $migration) { + // @todo Write a more general version rather than hard-coded. + $source_can_have_metatags = in_array($source->getPluginId(), [ + 'd7_node', + 'd7_node_revision', + 'taxonomy_term', + 'd7_user' + ]); + if ($source_can_have_metatags && $migration->getDestinationPlugin() instanceof EntityContentBase) { + $entity_type = NULL; + $entity_id = NULL; + $revision_id = NULL; + + // @todo Write a more general version rather than switch statement. + switch ($source->getPluginId()) { + case 'd7_node': + case 'd7_node_revision': + $entity_type = 'node'; + $entity_id = $row->getSourceProperty('nid'); + $revision_id = $row->getSourceProperty('vid'); + break; + + case 'taxonomy_term': + $entity_type = 'taxonomy_term'; + $entity_id = $row->getSourceProperty('tid'); + break; + + case 'd7_user': + $entity_type = 'user'; + $entity_id = $row->getSourceProperty('uid'); + break; + } + + /** @var SqlBase $source */ + /** @var SelectInterface $query */ + $query = $source->getDatabase()->select('metatag', 'm') + ->fields('m', ['data']) + ->condition('entity_type', $entity_type) + ->condition('entity_id', $entity_id); + if (!is_null($revision_id)) { + $query->condition('revision_id', $revision_id); + } + $metatag_value = []; + foreach ($query->execute() as $metatag_row) { + $metatag_value[]['value'] = $metatag_row->data; + } + $row->setSourceProperty('field_metatag', $metatag_value); + } +} + +/** + * Implements hook_migration_plugins_alter(). + * + * @param array $migrations + */ +function metatag_migration_plugins_alter(array &$migrations) { + foreach ($migrations as &$migration) { + if (isset($migration['destination']['plugin'])) { + $plugin_definition = \Drupal::service('plugin.manager.migrate.destination') + ->getDefinition($migration['destination']['plugin']); + $destination_plugin = DefaultFactory::getPluginClass($migration['destination']['plugin'], $plugin_definition); + $entity_content_base = 'Drupal\migrate\Plugin\migrate\destination\EntityContentBase'; + + if (is_subclass_of($destination_plugin, $entity_content_base) || $destination_plugin == $entity_content_base) { + $migration['process']['field_metatag'] = 'field_metatag'; + $migration['migration_dependencies']['required'][] = 'd7_metatag_field_instance'; + } + } + } +} diff --git a/migration_templates/d7_metatag_field.yml b/migration_templates/d7_metatag_field.yml new file mode 100644 index 0000000..0b6f0cd --- /dev/null +++ b/migration_templates/d7_metatag_field.yml @@ -0,0 +1,20 @@ +id: d7_metatag_field +label: Metatag field +migration_tags: + - Drupal 7 +source: + plugin: d7_metatag_field + ignore_map: true + constants: + status: true + langcode: und + field_name: field_metatag + type: metatag +process: + entity_type: entity_type + status: 'constants/status' + langcode: 'constants/langcode' + field_name: 'constants/field_name' + type: 'constants/type' +destination: + plugin: entity:field_storage_config diff --git a/migration_templates/d7_metatag_field_instance.yml b/migration_templates/d7_metatag_field_instance.yml new file mode 100644 index 0000000..371a60e --- /dev/null +++ b/migration_templates/d7_metatag_field_instance.yml @@ -0,0 +1,22 @@ +id: d7_metatag_field_instance +label: Metatag field instance +migration_tags: + - Drupal 7 +source: + plugin: d7_metatag_field_instance + ignore_map: true + constants: + field_name: field_metatag + label: Metatags +process: + entity_type: entity_type + field_name: 'constants/field_name' + bundle: bundle + label: 'constants/label' +destination: + plugin: entity:field_config +migration_dependencies: + required: + - d7_metatag_field + - d7_node_type + - d7_taxonomy_vocabulary diff --git a/migration_templates/d7_metatag_field_instance_widget_settings.yml b/migration_templates/d7_metatag_field_instance_widget_settings.yml new file mode 100644 index 0000000..fae4027 --- /dev/null +++ b/migration_templates/d7_metatag_field_instance_widget_settings.yml @@ -0,0 +1,20 @@ +id: d7_metatag_field_instance_widget_settings +label: Metatag field instance widget settings +migration_tags: + - Drupal 7 +source: + plugin: d7_metatag_field_instance + ignore_map: true + constants: + form_mode: default + field_name: field_metatag +process: + bundle: bundle + form_mode: 'constants/form_mode' + field_name: 'constants/field_name' + entity_type: entity_type +destination: + plugin: component_entity_form_display +migration_dependencies: + required: + - d7_metatag_field_instance diff --git a/src/Plugin/migrate/source/d7/MetatagField.php b/src/Plugin/migrate/source/d7/MetatagField.php new file mode 100644 index 0000000..48fb524 --- /dev/null +++ b/src/Plugin/migrate/source/d7/MetatagField.php @@ -0,0 +1,46 @@ +select('metatag', 'm') + ->fields('m', ['entity_type']) + ->groupBy('entity_type'); + } + + /** + * {@inheritdoc} + */ + public function fields() { + $fields = array('entity_type' => $this->t('Entity type')); + return $fields; + } + + /** + * {@inheritdoc} + */ + public function getIds() { + $ids['entity_type']['type'] = 'string'; + return $ids; + } + +} diff --git a/src/Plugin/migrate/source/d7/MetatagFieldInstance.php b/src/Plugin/migrate/source/d7/MetatagFieldInstance.php new file mode 100644 index 0000000..b41305a --- /dev/null +++ b/src/Plugin/migrate/source/d7/MetatagFieldInstance.php @@ -0,0 +1,69 @@ +select('metatag', 'm') + ->fields('m', ['entity_type']) + ->groupBy('entity_type'); + } + + /** + * {@inheritdoc} + */ + public function fields() { + return array( + 'entity_type' => $this->t('Entity type'), + 'bundle' => $this->t('Bundle'), + ); + } + + /** + * Returns each entity_type/bundle pair. + */ + public function initializeIterator() { + $bundles = []; + foreach (parent::initializeIterator() as $instance) { + $bundle_info = \Drupal::getContainer() + ->get('entity_type.bundle.info') + ->getBundleInfo($instance['entity_type']); + foreach (array_keys($bundle_info) as $bundle) { + $bundles[] = [ + 'entity_type' => $instance['entity_type'], + 'bundle' => $bundle + ]; + } + } + return new \ArrayIterator($bundles); + } + + /** + * {@inheritdoc} + */ + public function getIds() { + $ids['entity_type']['type'] = 'string'; + $ids['bundle']['type'] = 'string'; + return $ids; + } + +} diff --git a/tests/fixtures/drupal7.php b/tests/fixtures/drupal7.php new file mode 100644 index 0000000..90ec8e9 --- /dev/null +++ b/tests/fixtures/drupal7.php @@ -0,0 +1,170 @@ +schema()->createTable('metatag', array( + 'fields' => array( + 'entity_type' => array( + 'type' => 'varchar', + 'not null' => TRUE, + 'length' => '32', + 'default' => '', + ), + 'entity_id' => array( + 'type' => 'int', + 'not null' => TRUE, + 'size' => 'normal', + 'default' => '0', + 'unsigned' => TRUE, + ), + 'revision_id' => array( + 'type' => 'int', + 'not null' => TRUE, + 'size' => 'normal', + 'default' => '0', + 'unsigned' => TRUE, + ), + 'language' => array( + 'type' => 'varchar', + 'not null' => TRUE, + 'length' => '32', + 'default' => '', + ), + 'data' => array( + 'type' => 'blob', + 'not null' => TRUE, + 'size' => 'big', + ), + ), + 'primary key' => array( + 'entity_type', + 'entity_id', + 'revision_id', + 'language', + ), + 'indexes' => array( + 'type_revision' => array( + 'entity_type', + 'revision_id', + ), + ), + 'mysql_character_set' => 'utf8', +)); + +$connection->insert('metatag') +->fields(array( + 'entity_type', + 'entity_id', + 'revision_id', + 'language', + 'data', +)) +->values(array( + 'entity_type' => 'node', + 'entity_id' => '3', + 'revision_id' => '3', + 'language' => 'und', + 'data' => 'a:1:{s:8:"keywords";a:1:{s:5:"value";s:15:"keynoderevision";}}', +)) +->values(array( + 'entity_type' => 'node', + 'entity_id' => '3', + 'revision_id' => '4', + 'language' => 'und', + 'data' => 'a:1:{s:8:"keywords";a:1:{s:5:"value";s:7:"keynode";}}', +)) +->values(array( + 'entity_type' => 'user', + 'entity_id' => '2', + 'revision_id' => '0', + 'language' => 'und', + 'data' => 'a:1:{s:8:"keywords";a:1:{s:5:"value";s:7:"keyuser";}}', +)) +->values(array( + 'entity_type' => 'taxonomy_term', + 'entity_id' => '2', + 'revision_id' => '0', + 'language' => 'und', + 'data' => 'a:1:{s:8:"keywords";a:1:{s:5:"value";s:12:"keytaxonomy2";}}', +)) +->execute(); + +$connection->insert('node') +->fields(array( + 'nid', + 'vid', + 'type', + 'language', + 'title', + 'uid', + 'status', + 'created', + 'changed', + 'comment', + 'promote', + 'sticky', + 'tnid', + 'translate', +)) +->values(array( + 'nid' => '3', + 'vid' => '4', + 'type' => 'test_content_type', + 'language' => 'en', + 'title' => 'An Edited Node', + 'uid' => '2', + 'status' => '1', + 'created' => '1421727515', + 'changed' => '1441032132', + 'comment' => '2', + 'promote' => '1', + 'sticky' => '0', + 'tnid' => '0', + 'translate' => '0', +)) +->execute(); + +$connection->insert('node_revision') +->fields(array( + 'nid', + 'vid', + 'uid', + 'title', + 'log', + 'timestamp', + 'status', + 'comment', + 'promote', + 'sticky', +)) +->values(array( + 'nid' => '3', + 'vid' => '3', + 'uid' => '1', + 'title' => 'A Node', + 'log' => '', + 'timestamp' => '1441032131', + 'status' => '1', + 'comment' => '2', + 'promote' => '1', + 'sticky' => '0', +)) +->values(array( + 'nid' => '3', + 'vid' => '4', + 'uid' => '1', + 'title' => 'An Edited Node', + 'log' => '', + 'timestamp' => '1441032132', + 'status' => '1', + 'comment' => '2', + 'promote' => '1', + 'sticky' => '0', +)) +->execute(); diff --git a/tests/src/Kernel/Migrate/MigrateMetatagTest.php b/tests/src/Kernel/Migrate/MigrateMetatagTest.php new file mode 100644 index 0000000..b7ba330 --- /dev/null +++ b/tests/src/Kernel/Migrate/MigrateMetatagTest.php @@ -0,0 +1,93 @@ +loadFixture(__DIR__ . '/../../../../tests/fixtures/drupal7.php'); + + $this->installEntitySchema('node'); + $this->installEntitySchema('comment'); + $this->installEntitySchema('taxonomy_term'); + $this->installEntitySchema('file'); + $this->installConfig(static::$modules); + $this->installSchema('node', ['node_access']); + $this->installSchema('system', ['sequences']); + + $this->executeMigrations([ + 'd7_metatag_field', + 'd7_node_type', + 'd7_taxonomy_vocabulary', + 'd7_metatag_field_instance', + 'd7_metatag_field_instance_widget_settings', + 'd7_user_role', + 'd7_user', + 'd7_comment_type', + 'd7_field', + 'd7_field_instance', + 'd7_node:test_content_type', + 'd7_node:article', + 'd7_node_revision:test_content_type', + 'd7_taxonomy_term', + ]); + } + + /** + * Test metatag migration from Drupal 7 to 8. + */ + public function testMetatag() { + /** @var Node $node */ + $node = Node::load(3); + $this->assertTrue($node instanceof NodeInterface); + $this->assertTrue($node->hasField('field_metatag')); + $this->assertSame('a:1:{s:8:"keywords";a:1:{s:5:"value";s:7:"keynode";}}', $node->field_metatag->value); + + $node = node_revision_load(3); + $this->assertTrue($node instanceof NodeInterface); + $this->assertTrue($node->hasField('field_metatag')); + $this->assertSame('a:1:{s:8:"keywords";a:1:{s:5:"value";s:15:"keynoderevision";}}', $node->field_metatag->value); + + /** @var User $user */ + $user = User::load(2); + $this->assertTrue($user instanceof UserInterface); + $this->assertTrue($user->hasField('field_metatag')); + $this->assertSame('a:1:{s:8:"keywords";a:1:{s:5:"value";s:7:"keyuser";}}', $user->field_metatag->value); + + /** @var Term $term */ + $term = Term::load(2); + $this->assertTrue($term instanceof TermInterface); + $this->assertTrue($term->hasField('field_metatag')); + $this->assertSame('a:1:{s:8:"keywords";a:1:{s:5:"value";s:12:"keytaxonomy2";}}', $term->field_metatag->value); + } +}