Issue #2530030 by phenaproxima, mikeryan, benjy: Create the migrate builder plugin type
parent
bd1dbf55cb
commit
b95a4815c9
|
@ -20,4 +20,4 @@ destination:
|
|||
plugin: book
|
||||
migration_dependencies:
|
||||
required:
|
||||
- d6_node
|
||||
- d6_node:*
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,9 @@ migrate.migration.*:
|
|||
destination:
|
||||
type: migrate.destination.[plugin]
|
||||
label: 'Destination'
|
||||
template:
|
||||
type: string
|
||||
label: 'Template'
|
||||
migration_dependencies:
|
||||
type: mapping
|
||||
label: 'Dependencies'
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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}
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -14,4 +14,4 @@ destination:
|
|||
migration_dependencies:
|
||||
required:
|
||||
- d6_cck_field_values
|
||||
- d6_node_revision
|
||||
- d6_node_revision:*
|
||||
|
|
|
@ -16,6 +16,6 @@ destination:
|
|||
plugin: entity:node
|
||||
migration_dependencies:
|
||||
required:
|
||||
- d6_node
|
||||
- d6_node:*
|
||||
- d6_field_formatter_settings
|
||||
- d6_field_instance_widget_settings
|
||||
|
|
|
@ -24,5 +24,5 @@ destination:
|
|||
migration_dependencies:
|
||||
required:
|
||||
- d6_file
|
||||
- d6_node
|
||||
- d6_node:*
|
||||
- d6_upload_field_instance
|
||||
|
|
|
@ -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')
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -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];
|
||||
}
|
||||
|
||||
}
|
|
@ -2,6 +2,8 @@ id: d6_node
|
|||
label: Drupal 6 nodes
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
builder:
|
||||
plugin: d6_node
|
||||
source:
|
||||
plugin: d6_node
|
||||
process:
|
||||
|
|
|
@ -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:*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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:*
|
||||
|
|
|
@ -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:*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue