Issue #2530030 by phenaproxima, mikeryan, benjy: Create the migrate builder plugin type

8.0.x
webchick 2015-08-05 15:29:03 -07:00
parent bd1dbf55cb
commit b95a4815c9
29 changed files with 826 additions and 48 deletions

View File

@ -20,4 +20,4 @@ destination:
plugin: book
migration_dependencies:
required:
- d6_node
- d6_node:*

View File

@ -2,6 +2,9 @@ id: d6_field
label: Drupal 6 field configuration
migration_tags:
- Drupal 6
builder:
plugin: d6_cck_migration
cck_plugin_method: processField
source:
plugin: d6_field
constants:

View File

@ -2,6 +2,9 @@ id: d6_field_formatter_settings
label: Drupal 6 field formatter configuration
migration_tags:
- Drupal 6
builder:
plugin: d6_cck_migration
cck_plugin_method: processFieldFormatter
source:
plugin: d6_field_instance_per_view_mode
constants:

View File

@ -2,6 +2,9 @@ id: d6_field_instance
label: Drupal 6 field instance configuration
migration_tags:
- Drupal 6
builder:
plugin: d6_cck_migration
cck_plugin_method: processFieldInstance
source:
plugin: d6_field_instance
constants:

View File

@ -2,6 +2,9 @@ id: d6_field_instance_widget_settings
label: Drupal 6 field instance widget configuration
migration_tags:
- Drupal 6
builder:
plugin: d6_cck_migration
cck_plugin_method: processFieldWidget
source:
plugin: d6_field_instance_per_form_display
constants:

View File

@ -24,28 +24,12 @@ class FieldInstance extends DrupalSqlBase {
* {@inheritdoc}
*/
public function query() {
$query = $this->select('content_node_field_instance', 'cnfi')
->fields('cnfi', array(
'field_name',
'type_name',
'weight',
'label',
'widget_type',
'widget_settings',
'display_settings',
'description',
'widget_module',
'widget_active',
'description',
))
->fields('cnf', array(
'required',
'active',
'global_settings',
));
$query = $this->select('content_node_field_instance', 'cnfi')->fields('cnfi');
if (isset($this->configuration['node_type'])) {
$query->condition('cnfi.type_name', $this->configuration['node_type']);
}
$query->join('content_node_field', 'cnf', 'cnf.field_name = cnfi.field_name');
$query->orderBy('weight');
$query->fields('cnf');
return $query;
}

View File

@ -28,6 +28,9 @@ migrate.migration.*:
destination:
type: migrate.destination.[plugin]
label: 'Destination'
template:
type: string
label: 'Template'
migration_dependencies:
type: mapping
label: 'Dependencies'

View File

@ -8,6 +8,9 @@ services:
migrate.template_storage:
class: Drupal\migrate\MigrateTemplateStorage
arguments: ['@module_handler']
migrate.migration_builder:
class: Drupal\migrate\MigrationBuilder
arguments: ['@plugin.manager.migrate.builder']
plugin.manager.migrate.source:
class: Drupal\migrate\Plugin\MigratePluginManager
arguments: [source, '@container.namespaces', '@cache.discovery', '@module_handler', 'Drupal\migrate\Annotation\MigrateSource']
@ -20,3 +23,6 @@ services:
plugin.manager.migrate.id_map:
class: Drupal\migrate\Plugin\MigratePluginManager
arguments: [id_map, '@container.namespaces', '@cache.discovery', '@module_handler']
plugin.manager.migrate.builder:
class: Drupal\migrate\Plugin\MigratePluginManager
arguments: [builder, '@container.namespaces', '@cache.discovery', '@module_handler']

View File

@ -232,6 +232,13 @@ class Migration extends ConfigEntityBase implements MigrationInterface, Requirem
*/
protected $dependencies = [];
/**
* The ID of the template from which this migration was derived, if any.
*
* @var string|NULL
*/
protected $template;
/**
* The entity manager.
*

View File

@ -0,0 +1,69 @@
<?php
/**
* @file
* Contains \Drupal\migrate\MigrationBuilder.
*/
namespace Drupal\migrate;
use Drupal\migrate\Entity\Migration;
use Drupal\migrate\Plugin\MigratePluginManager;
/**
* Builds migration entities from migration templates.
*/
class MigrationBuilder {
/**
* The builder plugin manager.
*
* @var \Drupal\migrate\Plugin\MigratePluginManager
*/
protected $builderManager;
/**
* Constructs a MigrationBuilder.
*
* @param \Drupal\migrate\Plugin\MigratePluginManager $builder_manager
* The builder plugin manager.
*/
public function __construct(MigratePluginManager $builder_manager) {
$this->builderManager = $builder_manager;
}
/**
* Builds migration entities from templates.
*
* @param array $templates
* The parsed templates (each of which is an array parsed from YAML), keyed
* by ID.
*
* @return \Drupal\migrate\Entity\MigrationInterface[]
* The migration entities derived from the templates.
*/
public function createMigrations(array $templates) {
/** @var \Drupal\migrate\Entity\MigrationInterface[] $migrations */
$migrations = [];
foreach ($templates as $template_id => $template) {
if (isset($template['builder'])) {
$variants = $this->builderManager
->createInstance($template['builder']['plugin'], $template['builder'])
->buildMigrations($template);
}
else {
$variants = array(Migration::create($template));
}
/** @var \Drupal\migrate\Entity\MigrationInterface[] $variants */
foreach ($variants as $variant) {
$variant->set('template', $template_id);
}
$migrations = array_merge($migrations, $variants);
}
return $migrations;
}
}

View File

@ -8,13 +8,110 @@
namespace Drupal\migrate;
use Drupal\Component\Graph\Graph;
use Drupal\Component\Uuid\UuidInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\Entity\ConfigEntityStorage;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\Query\QueryFactoryInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Storage for migration entities.
*/
class MigrationStorage extends ConfigEntityStorage implements MigrateBuildDependencyInterface {
/**
* The entity query factory service.
*
* @var \Drupal\Core\Entity\Query\QueryFactoryInterface
*/
protected $queryFactory;
/**
* Constructs a MigrationStorage object.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* An entity type definition.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory service.
* @param \Drupal\Component\Uuid\UuidInterface $uuid_service
* The UUID service.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Entity\Query\QueryFactoryInterface $query_factory
* The entity query factory service.
*/
public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, QueryFactoryInterface $query_factory) {
parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager);
$this->queryFactory = $query_factory;
}
/**
* {@inheritdoc}
*/
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
return new static(
$entity_type,
$container->get('config.factory'),
$container->get('uuid'),
$container->get('language_manager'),
$container->get('entity.query.config')
);
}
/**
* {@inheritdoc}
*/
public function loadMultiple(array $ids = NULL) {
/** @var \Drupal\migrate\Entity\MigrationInterface[] $migrations */
$migrations = parent::loadMultiple($ids);
foreach ($migrations as $migration) {
$migration->set('migration_dependencies', $this->expandDependencies($migration->getMigrationDependencies()));
}
return $migrations;
}
/**
* Expands template dependencies.
*
* Migration dependencies which match the template_id:* pattern are a signal
* that the migration depends on every variant of template_id. This method
* queries for those variant IDs and splices them into the list of
* dependencies.
*
* @param array $dependencies
* The original migration dependencies (with template IDs), organized by
* group (required, optional, etc.)
*
* @return array
* The expanded list of dependencies, organized by group.
*/
protected function expandDependencies(array $dependencies) {
$expanded_dependencies = [];
foreach (array_keys($dependencies) as $group) {
$expanded_dependencies[$group] = [];
foreach ($dependencies[$group] as $dependency_id) {
if (substr($dependency_id, -2) == ':*') {
$template_id = substr($dependency_id, 0, -2);
$variants = $this->queryFactory->get($this->entityType, 'OR')
->condition('id', $template_id)
->condition('template', $template_id)
->execute();
$expanded_dependencies[$group] = array_merge($expanded_dependencies[$group], $variants);
}
else {
$expanded_dependencies[$group][] = $dependency_id;
}
}
}
return $expanded_dependencies;
}
/**
* {@inheritdoc}
*/

View File

@ -0,0 +1,31 @@
<?php
/**
* @file
* Contains \Drupal\migrate\Plugin\MigrateBuilderInterface.
*/
namespace Drupal\migrate\Plugin;
/**
* Defines the builder plugin type.
*
* Builder plugins implement custom logic to generate migration entities from
* migration templates. For example, a migration may need to be customized
* based on data that's present in the source database; such customization is
* implemented by builders.
*/
interface MigrateBuilderInterface {
/**
* Builds migration entities based on a template.
*
* @param array $template
* The parsed template.
*
* @return \Drupal\migrate\Entity\MigrationInterface[]
* The unsaved migrations generated from the template.
*/
public function buildMigrations(array $template);
}

View File

@ -0,0 +1,52 @@
<?php
/**
* @file
* Contains \Drupal\migrate\Plugin\migrate\builder\BuilderBase.
*/
namespace Drupal\migrate\Plugin\migrate\builder;
use Drupal\Core\Plugin\PluginBase;
use Drupal\migrate\Entity\Migration;
use Drupal\migrate\Plugin\MigrateBuilderInterface;
/**
* Base class for builder plugins.
*/
abstract class BuilderBase extends PluginBase implements MigrateBuilderInterface {
/**
* Returns a fully initialized instance of a source plugin.
*
* @param string $plugin_id
* The plugin ID.
* @param array $configuration
* (optional) Additional configuration for the plugin.
*
* @return \Drupal\migrate\Plugin\MigrateSourceInterface
* The fully initialized source plugin.
*/
protected function getSourcePlugin($plugin_id, array $configuration = []) {
$configuration['plugin'] = $plugin_id;
// By default, SqlBase subclasses will try to join on a map table. But in
// this case we're trying to use the source plugin as a detached iterator
// over the source data, so we don't want to join on (or create) the map
// table.
// @see SqlBase::initializeIterator()
$configuration['ignore_map'] = TRUE;
// Source plugins are tightly coupled to migration entities, so we need
// to create a fake migration in order to properly initialize the plugin.
$values = [
'id' => uniqid(),
'source' => $configuration,
// Since this isn't a real migration, we don't want a real destination --
// the 'null' destination is perfect for this.
'destination' => [
'plugin' => 'null',
],
];
return Migration::create($values)->getSourcePlugin();
}
}

View File

@ -133,7 +133,7 @@ abstract class SqlBase extends SourcePluginBase {
// OR above high water).
$conditions = $this->query->orConditionGroup();
$condition_added = FALSE;
if ($this->mapJoinable()) {
if (empty($this->configuration['ignore_map']) && $this->mapJoinable()) {
// Build the join to the map table. Because the source key could have
// multiple fields, we need to build things up.
$count = 1;

View File

@ -28,29 +28,41 @@ abstract class MigrateTestCase extends UnitTestCase {
$this->migrationConfiguration += ['migrationClass' => 'Drupal\migrate\Entity\Migration'];
$this->idMap = $this->getMock('Drupal\migrate\Plugin\MigrateIdMapInterface');
$this->idMap->expects($this->any())
$this->idMap
->method('getQualifiedMapTableName')
->will($this->returnValue('test_map'));
->willReturn('test_map');
$migration = $this->getMockBuilder($this->migrationConfiguration['migrationClass'])
->disableOriginalConstructor()
->getMock();
$migration->expects($this->any())
->method('checkRequirements')
->will($this->returnValue(TRUE));
$migration->expects($this->any())
->method('getIdMap')
->will($this->returnValue($this->idMap));
$migration->method('checkRequirements')
->willReturn(TRUE);
$migration->method('getIdMap')
->willReturn($this->idMap);
$migration->method('getMigrationDependencies')
->willReturn([
'required' => [],
'optional' => [],
]);
$configuration = &$this->migrationConfiguration;
$migration->expects($this->any())->method('get')->will($this->returnCallback(function ($argument) use (&$configuration) {
return isset($configuration[$argument]) ? $configuration[$argument] : '';
}));
$migration->expects($this->any())->method('set')->will($this->returnCallback(function ($argument, $value) use (&$configuration) {
$migration->method('get')
->willReturnCallback(function ($argument) use (&$configuration) {
return isset($configuration[$argument]) ? $configuration[$argument] : '';
});
$migration->method('set')
->willReturnCallback(function ($argument, $value) use (&$configuration) {
$configuration[$argument] = $value;
}));
$migration->expects($this->any())
->method('id')
->will($this->returnValue($configuration['id']));
});
$migration->method('id')
->willReturn($configuration['id']);
return $migration;
}

View File

@ -0,0 +1,130 @@
<?php
/**
* @file
* Contains \Drupal\Tests\migrate\Unit\MigrationStorageTest.
*/
namespace Drupal\Tests\migrate\Unit;
use Drupal\Component\Uuid\UuidInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\Query\QueryFactoryInterface;
use Drupal\Core\Entity\Query\QueryInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\migrate\MigrationStorage;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\migrate\MigrationStorage
* @group migrate
*/
class MigrationStorageTest extends UnitTestCase {
/**
* @var \Drupal\Tests\migrate\Unit\TestMigrationStorage
*/
protected $storage;
/**
* @var \Drupal\Core\Entity\Query\QueryInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $query;
/**
* {@inheritdoc}
*/
public function setUp() {
$this->query = $this->getMock(QueryInterface::class);
$this->query->method('condition')
->willReturnSelf();
$query_factory = $this->getMock(QueryFactoryInterface::class);
$query_factory->method('get')
->willReturn($this->query);
$this->storage = new TestMigrationStorage(
$this->getMock(EntityTypeInterface::class),
$this->getMock(ConfigFactoryInterface::class),
$this->getMock(UuidInterface::class),
$this->getMock(LanguageManagerInterface::class),
$query_factory
);
}
/**
* Tests expandDependencies() when variants exist.
*
* @covers ::expandDependencies
*/
public function testExpandDependenciesWithVariants() {
$this->query->method('execute')
->willReturn(['d6_node__page', 'd6_node__article']);
$dependencies = [
'required' => [
'd6_node:*',
'd6_user',
],
];
$dependencies = $this->storage->expandDependencies($dependencies);
$this->assertSame(['d6_node__page', 'd6_node__article', 'd6_user'], $dependencies['required']);
}
/**
* Tests expandDependencies() when no variants exist.
*
* @covers ::expandDependencies
*/
public function testExpandDependenciesNoVariants() {
$this->query->method('execute')
->willReturn([]);
$dependencies = [
'required' => [
'd6_node:*',
'd6_user',
],
];
$dependencies = $this->storage->expandDependencies($dependencies);
$this->assertSame(['d6_user'], $dependencies['required']);
}
/**
* Tests expandDependencies() when no variants exist and there are no static
* (non-variant) dependencies.
*
* @covers ::expandDependencies
*/
public function testExpandDependenciesNoVariantsOrStaticDependencies() {
$this->query->method('execute')
->willReturn([]);
$dependencies = [
'required' => [
'd6_node:*',
'd6_node_revision:*',
],
];
$dependencies = $this->storage->expandDependencies($dependencies);
$this->assertSame([], $dependencies['required']);
}
}
/**
* Test version of \Drupal\migrate\MigrationStorage.
*
* Exposes protected methods for testing.
*/
class TestMigrationStorage extends MigrationStorage {
/**
* {@inheritdoc}
*/
public function expandDependencies(array $dependencies) {
return parent::expandDependencies($dependencies);
}
}

View File

@ -14,4 +14,4 @@ destination:
migration_dependencies:
required:
- d6_cck_field_values
- d6_node_revision
- d6_node_revision:*

View File

@ -16,6 +16,6 @@ destination:
plugin: entity:node
migration_dependencies:
required:
- d6_node
- d6_node:*
- d6_field_formatter_settings
- d6_field_instance_widget_settings

View File

@ -24,5 +24,5 @@ destination:
migration_dependencies:
required:
- d6_file
- d6_node
- d6_node:*
- d6_upload_field_instance

View File

@ -12,6 +12,7 @@ use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityStorageException;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\Query\QueryFactoryInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\migrate\Plugin\migrate\source\SourcePluginBase;
use Drupal\migrate_drupal\Plugin\CckFieldMigrateSourceInterface;
@ -47,11 +48,13 @@ class MigrationStorage extends BaseMigrationStorage {
* The UUID service.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Entity\Query\QueryFactoryInterface $query_factory
* The entity query factory.
* @param \Drupal\migrate_drupal\Plugin\MigratePluginManager
* The cckfield plugin manager.
*/
public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, MigratePluginManager $cck_plugin_manager) {
parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager);
public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, QueryFactoryInterface $query_factory, MigratePluginManager $cck_plugin_manager) {
parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager, $query_factory);
$this->cckPluginManager = $cck_plugin_manager;
}
@ -64,6 +67,7 @@ class MigrationStorage extends BaseMigrationStorage {
$container->get('config.factory'),
$container->get('uuid'),
$container->get('language_manager'),
$container->get('entity.query.config'),
$container->get('plugin.manager.migrate.cckfield')
);
}

View File

@ -0,0 +1,56 @@
<?php
/**
* @file
* Contains \Drupal\migrate_drupal\Plugin\migrate\builder\d6\CckBuilder.
*/
namespace Drupal\migrate_drupal\Plugin\migrate\builder\d6;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\migrate\Plugin\migrate\builder\BuilderBase;
use Drupal\migrate\Plugin\MigratePluginManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Base class for builders which leverage cckfield plugins.
*/
abstract class CckBuilder extends BuilderBase implements ContainerFactoryPluginInterface {
/**
* The cckfield plugin manager.
*
* @var \Drupal\migrate\Plugin\MigratePluginManager
*/
protected $cckPluginManager;
/**
* Constructs a CckBuilder.
*
* @param array $configuration
* Plugin configuration.
* @param string $plugin_id
* The plugin ID.
* @param mixed $plugin_definition
* The plugin definition.
* @param \Drupal\migrate\Plugin\MigratePluginManager $cck_manager
* The cckfield plugin manager.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigratePluginManager $cck_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->cckPluginManager = $cck_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('plugin.manager.migrate.cckfield')
);
}
}

View File

@ -0,0 +1,53 @@
<?php
/**
* @file
* Contains \Drupal\migrate_drupal\Plugin\migrate\builder\d6\CckMigration.
*/
namespace Drupal\migrate_drupal\Plugin\migrate\builder\d6;
use Drupal\migrate\Entity\Migration;
/**
* @PluginID("d6_cck_migration")
*/
class CckMigration extends CckBuilder {
/**
* List of cckfield plugin IDs which have already run.
*
* @var string[]
*/
protected $processedFieldTypes = [];
/**
* {@inheritdoc}
*/
public function buildMigrations(array $template) {
$migration = Migration::create($template);
// Loop through every field that will be migrated.
foreach ($migration->getSourcePlugin() as $field) {
$field_type = $field->getSourceProperty('type');
// Each field type should only be processed once.
if (in_array($field_type, $this->processedFieldTypes)) {
continue;
}
// Only process the current field type if a relevant cckfield plugin
// exists.
elseif ($this->cckPluginManager->hasDefinition($field_type)) {
$this->processedFieldTypes[] = $field_type;
// Allow the cckfield plugin to alter the migration as necessary so that
// it knows how to handle fields of this type.
$this->cckPluginManager
->createInstance($field_type, [], $migration)
->{$this->configuration['cck_plugin_method']}($migration);
}
}
return [$migration];
}
}

View File

@ -2,6 +2,8 @@ id: d6_node
label: Drupal 6 nodes
migration_tags:
- Drupal 6
builder:
plugin: d6_node
source:
plugin: d6_node
process:

View File

@ -2,6 +2,8 @@ id: d6_node_revision
label: Drupal 6 node revisions
migration_tags:
- Drupal 6
builder:
plugin: d6_node
source:
plugin: d6_node_revision
process:
@ -39,4 +41,4 @@ destination:
plugin: entity_revision:node
migration_dependencies:
required:
- d6_node
- d6_node:*

View File

@ -0,0 +1,75 @@
<?php
/**
* @file
* Contains \Drupal\node\Plugin\migrate\builder\d6\Node.
*/
namespace Drupal\node\Plugin\migrate\builder\d6;
use Drupal\migrate\Entity\Migration;
use Drupal\migrate\Entity\MigrationInterface;
use Drupal\migrate_drupal\Plugin\migrate\builder\d6\CckBuilder;
/**
* @PluginID("d6_node")
*/
class Node extends CckBuilder {
/**
* Already-instantiated cckfield plugins, keyed by ID.
*
* @var \Drupal\migrate_drupal\Plugin\MigrateCckFieldInterface[]
*/
protected $cckPluginCache = [];
/**
* Gets a cckfield plugin instance.
*
* @param string $field_type
* The field type (plugin ID).
* @param \Drupal\migrate\Entity\MigrationInterface|NULL $migration
* The migration, if any.
*
* @return \Drupal\migrate_drupal\Plugin\MigrateCckFieldInterface
* The cckfield plugin instance.
*/
protected function getCckPlugin($field_type, MigrationInterface $migration = NULL) {
if (empty($this->cckPluginCache[$field_type])) {
$this->cckPluginCache[$field_type] = $this->cckPluginManager->createInstance($field_type, [], $migration);
}
return $this->cckPluginCache[$field_type];
}
/**
* {@inheritdoc}
*/
public function buildMigrations(array $template) {
$migrations = [];
foreach ($this->getSourcePlugin('d6_node_type', $template['source']) as $row) {
$node_type = $row->getSourceProperty('type');
$values = $template;
$values['id'] = $template['id'] . '__' . $node_type;
$migration = Migration::create($values);
$fields = $this->getSourcePlugin('d6_field_instance', ['node_type' => $node_type] + $template['source']);
foreach ($fields as $field) {
$data = $field->getSource();
if ($this->cckPluginManager->hasDefinition($data['type'])) {
$this->getCckPlugin($data['type'])
->processCckFieldValues($migration, $data['field_name'], $data);
}
else {
$migration->setProcessOfProperty($data['field_name'], $data['field_name']);
}
}
$migrations[] = $migration;
}
return $migrations;
}
}

View File

@ -0,0 +1,70 @@
<?php
/**
* @file
* Contains \Drupal\node\Tests\Migrate\d6\MigrateNodeBuilderTest.
*/
namespace Drupal\node\Tests\Migrate\d6;
use Drupal\migrate_drupal\Tests\d6\MigrateDrupal6TestBase;
/**
* @group node
*/
class MigrateNodeBuilderTest extends MigrateDrupal6TestBase {
public static $modules = ['migrate', 'migrate_drupal', 'node'];
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$this->loadDumps([
'ContentNodeField.php',
'ContentNodeFieldInstance.php',
'NodeType.php',
]);
}
/**
* Tests creating migrations from a template, using a builder plugin.
*/
public function testCreateMigrations() {
$templates = [
'd6_node' => [
'id' => 'd6_node',
'builder' => [
'plugin' => 'd6_node',
],
'source' => [
'plugin' => 'd6_node',
],
'process' => [
'nid' => 'nid',
'vid' => 'vid',
'uid' => 'uid',
],
'destination' => [
'plugin' => 'entity:node',
],
],
];
$migrations = \Drupal::service('migrate.migration_builder')->createMigrations($templates);
$this->assertIdentical(11, count($migrations));
$this->assertIdentical('d6_node__article', $migrations[0]->id());
$this->assertIdentical('d6_node__company', $migrations[1]->id());
$this->assertIdentical('d6_node__employee', $migrations[2]->id());
$this->assertIdentical('d6_node__event', $migrations[3]->id());
$this->assertIdentical('d6_node__page', $migrations[4]->id());
$this->assertIdentical('d6_node__sponsor', $migrations[5]->id());
$this->assertIdentical('d6_node__story', $migrations[6]->id());
$this->assertIdentical('d6_node__test_event', $migrations[7]->id());
$this->assertIdentical('d6_node__test_page', $migrations[8]->id());
$this->assertIdentical('d6_node__test_planet', $migrations[9]->id());
$this->assertIdentical('d6_node__test_story', $migrations[10]->id());
}
}

View File

@ -2,6 +2,8 @@ id: d6_term_node
label: Drupal 6 term/node relationships
migration_tags:
- Drupal 6
builder:
plugin: d6_term_node
load:
plugin: d6_term_node
@ -19,4 +21,4 @@ migration_dependencies:
required:
- d6_vocabulary_entity_display
- d6_vocabulary_entity_form_display
- d6_node
- d6_node:*

View File

@ -2,6 +2,8 @@ id: d6_term_node_revision
label: Drupal 6 term/node relationship revisions
migration_tags:
- Drupal 6
builder:
plugin: d6_term_node
load:
plugin: d6_term_node
bundle_migration: d6_vocabulary_field
@ -18,5 +20,5 @@ destination:
plugin: entity_revision:node
migration_dependencies:
required:
- d6_term_node
- d6_node_revision
- d6_term_node:*
- d6_node_revision:*

View File

@ -0,0 +1,109 @@
<?php
/**
* @file
* Contains \Drupal\taxonomy\Plugin\migrate\builder\d6\TermNode.
*/
namespace Drupal\taxonomy\Plugin\migrate\builder\d6;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\migrate\Entity\Migration;
use Drupal\migrate\MigrateExecutable;
use Drupal\migrate\MigrateMessage;
use Drupal\migrate\MigrateTemplateStorage;
use Drupal\migrate\Plugin\migrate\builder\BuilderBase;
use Drupal\migrate\Row;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* @PluginID("d6_term_node")
*/
class TermNode extends BuilderBase implements ContainerFactoryPluginInterface {
/**
* The migration template storage service.
*
* @var \Drupal\migrate\MigrateTemplateStorage
*/
protected $templateStorage;
/**
* Constructs a TermNode builder.
*
* @param array $configuration
* Plugin configuration.
* @param string $plugin_id
* The plugin ID.
* @param mixed $plugin_definition
* The plugin definition.
* @param \Drupal\migrate\MigrateTemplateStorage $template_storage
* The migration template storage handler.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrateTemplateStorage $template_storage) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->templateStorage = $template_storage;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('migrate.template_storage')
);
}
/**
* Builds a map of source vocabulary IDs to expected destination IDs.
*
* @param array $source
* Additional configuration for the d6_taxonomy_vocabulary source.
*
* @return array
* The vid map. The keys are the source IDs and the values are the
* (expected) destination IDs.
*/
protected function getVocabularyIdMap(array $source) {
$map = [];
$template = $this->templateStorage->getTemplateByName('d6_taxonomy_vocabulary');
$template['source'] += $source;
$migration = Migration::create($template);
$executable = new MigrateExecutable($migration, new MigrateMessage());
// Only process the destination ID properties.
$process = array_intersect_key($template['process'], $migration->getDestinationPlugin()->getIds());
foreach ($migration->getSourcePlugin()->getIterator() as $source_row) {
$row = new Row($source_row, $source_row);
// Process the row to generate the expected destination ID.
$executable->processRow($row, $process);
$map[$row->getSourceProperty('vid')] = $row->getDestinationProperty('vid');
}
return $map;
}
/**
* {@inheritdoc}
*/
public function buildMigrations(array $template) {
$migrations = [];
foreach ($this->getVocabularyIdMap($template['source']) as $source_vid => $destination_vid) {
$values = $template;
$values['id'] .= '__' . $source_vid;
$values['source']['vid'] = $source_vid;
$migration = Migration::create($values);
$migration->setProcessOfProperty($destination_vid, 'tid');
$migrations[] = $migration;
}
return $migrations;
}
}