Update to Drupal 8.1.5. For more information, see https://www.drupal.org/project/drupal/releases/8.1.5
This commit is contained in:
parent
13b6ca7cc2
commit
38ba7c357d
342 changed files with 7814 additions and 1534 deletions
|
@ -17,33 +17,30 @@ use Drupal\migrate\Row;
|
|||
* @section overview Overview of migration
|
||||
* Migration is an
|
||||
* @link http://wikipedia.org/wiki/Extract,_transform,_load Extract, Transform, Load @endlink
|
||||
* (ETL) process. For historical reasons, in the Drupal migration tool the
|
||||
* extract phase is called "source", the transform phase is called "process",
|
||||
* and the load phase is called "destination".
|
||||
* (ETL) process. In the Drupal migration API the extract phase is called
|
||||
* "source", the transform phase is called "process", and the load phase is
|
||||
* called "destination". It is important to understand that the "load" in ETL
|
||||
* means to load data into storage, while traditionally Drupal uses "load" to
|
||||
* mean load data from storage into memory.
|
||||
*
|
||||
* Source, process, and destination phases are each provided by plugins. Source
|
||||
* plugins extract data from a data source in "rows", containing "properties".
|
||||
* Each row is handed off to one or more series of process plugins, where each
|
||||
* series operates to transform the row data into one result property. After all
|
||||
* the properties are processed, the resulting row is handed off to a
|
||||
* destination plugin, which saves the data.
|
||||
* Source, process, and destination phases are each provided by plugins.
|
||||
* Source plugins extract data from a data source in "rows", containing
|
||||
* "properties". Each row is handed off to one or more process plugins which
|
||||
* transform the row's properties. After all the properties are processed, the
|
||||
* resulting row is handed off to a destination plugin, which saves the data.
|
||||
*
|
||||
* The Migrate module provides process plugins for common operations (setting
|
||||
* default values, mapping values, etc.), and destination plugins for Drupal
|
||||
* core objects (configuration, entity, URL alias, etc.). The Migrate Drupal
|
||||
* module provides source plugins to extract data from various versions of
|
||||
* Drupal. Custom and contributed modules can provide additional plugins; see
|
||||
* the @link plugin_api Plugin API topic @endlink for generic information about
|
||||
* providing plugins, and sections below for details about the plugin types.
|
||||
* A source plugin, one or more process plugins, and a destination plugin are
|
||||
* brought together to extract, transform, and load (in the ETL sense) a specific
|
||||
* type of data by a migration plugin.
|
||||
*
|
||||
* The configuration of migrations is stored in configuration entities, which
|
||||
* list the IDs and configurations of the plugins that are involved. See
|
||||
* @ref sec_entity below for details. To migrate an entire site, you'll need to
|
||||
* create a migration manifest; see @ref sec_manifest for details.
|
||||
*
|
||||
* https://www.drupal.org/node/2127611 has more complete information on the
|
||||
* Migration API, including information on load plugins, which are only used
|
||||
* in Drupal 6 migration.
|
||||
* @section sec_migrations Migration plugins
|
||||
* Migration plugin definitions are stored in a module's 'migrations' directory.
|
||||
* For backwards compatibility we also scan the 'migration_templates' directory.
|
||||
* Examples of migration plugin definitions can be found in
|
||||
* 'core/modules/action/migration_templates'. The plugin class is
|
||||
* \Drupal\migrate\Plugin\Migration, with interface
|
||||
* \Drupal\migrate\Plugin\MigrationInterface. Migration plugins are managed by
|
||||
* the \Drupal\migrate\Plugin\MigrationPluginManager class.
|
||||
*
|
||||
* @section sec_source Source plugins
|
||||
* Migration source plugins implement
|
||||
|
@ -61,7 +58,9 @@ use Drupal\migrate\Row;
|
|||
* with \Drupal\migrate\Annotation\MigrateProcessPlugin annotation, and must be
|
||||
* in namespace subdirectory Plugin\migrate\process under the namespace of the
|
||||
* module that defines them. Migration process plugins are managed by the
|
||||
* \Drupal\migrate\Plugin\MigratePluginManager class.
|
||||
* \Drupal\migrate\Plugin\MigratePluginManager class. The Migrate module
|
||||
* provides process plugins for common operations (setting default values,
|
||||
* mapping values, etc.).
|
||||
*
|
||||
* @section sec_destination Destination plugins
|
||||
* Migration destination plugins implement
|
||||
|
@ -70,34 +69,12 @@ use Drupal\migrate\Row;
|
|||
* annotated with \Drupal\migrate\Annotation\MigrateDestination annotation, and
|
||||
* must be in namespace subdirectory Plugin\migrate\destination under the
|
||||
* namespace of the module that defines them. Migration destination plugins
|
||||
* are managed by the
|
||||
* \Drupal\migrate\Plugin\MigrateDestinationPluginManager class.
|
||||
* are managed by the \Drupal\migrate\Plugin\MigrateDestinationPluginManager
|
||||
* class. The Migrate module provides destination plugins for Drupal core
|
||||
* objects (configuration and entity).
|
||||
*
|
||||
* @section sec_entity Migration configuration entities
|
||||
* The definition of how to migrate each type of data is stored in configuration
|
||||
* entities. The migration configuration entity class is
|
||||
* \Drupal\migrate\Entity\Migration, with interface
|
||||
* \Drupal\migrate\Entity\MigrationInterface; the configuration schema can be
|
||||
* found in the migrate.schema.yml file. Migration configuration consists of IDs
|
||||
* and configuration for the source, process, and destination plugins, as well
|
||||
* as information on dependencies. Process configuration consists of sections,
|
||||
* each of which defines the series of process plugins needed for one
|
||||
* destination property. You can find examples of migration configuration files
|
||||
* in the core/modules/migrate_drupal/config/install directory.
|
||||
*
|
||||
* @section sec_manifest Migration manifests
|
||||
* You can run a migration with the "drush migrate-manifest" command, providing
|
||||
* a migration manifest file. This file lists the configuration names of the
|
||||
* migrations you want to execute, as well as any dependencies they have (you
|
||||
* can find these in the "migration_dependencies" sections of the individual
|
||||
* configuration files). For example, to migrate blocks from a Drupal 6 site,
|
||||
* you would list:
|
||||
* @code
|
||||
* # Migrate blocks from Drupal 6 to 8
|
||||
* - d6_filter_format
|
||||
* - d6_custom_block
|
||||
* - d6_block
|
||||
* @endcode
|
||||
* @section sec_more_info More information
|
||||
* @link https://www.drupal.org/node/2127611 Migration API documentation. @endlink
|
||||
*
|
||||
* @see update_api
|
||||
* @}
|
||||
|
|
|
@ -662,7 +662,7 @@ class Migration extends PluginBase implements MigrationInterface, RequirementsIn
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMigrationDependencies() {
|
||||
return $this->migration_dependencies + ['required' => [], 'optional' => []];
|
||||
return ($this->migration_dependencies ?: []) + ['required' => [], 'optional' => []];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -703,14 +703,14 @@ class Migration extends PluginBase implements MigrationInterface, RequirementsIn
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTrackLastImported() {
|
||||
$this->trackLastImported;
|
||||
return $this->trackLastImported;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDestinationIds() {
|
||||
$this->destinationIds;
|
||||
return $this->destinationIds;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -88,6 +88,21 @@ abstract class Entity extends DestinationBase implements ContainerFactoryPluginI
|
|||
return substr($plugin_id, 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bundle for the row taking into account the default.
|
||||
*
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The current row we're importing.
|
||||
*
|
||||
* @return string
|
||||
* The bundle for this row.
|
||||
*/
|
||||
public function getBundle(Row $row) {
|
||||
$default_bundle = isset($this->configuration['default_bundle']) ? $this->configuration['default_bundle'] : '';
|
||||
$bundle_key = $this->getKey('bundle');
|
||||
return $row->getDestinationProperty($bundle_key) ?: $default_bundle;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -112,6 +127,11 @@ abstract class Entity extends DestinationBase implements ContainerFactoryPluginI
|
|||
$this->updateEntity($entity, $row);
|
||||
}
|
||||
else {
|
||||
// Attempt to ensure we always have a bundle.
|
||||
if ($bundle = $this->getBundle($row)) {
|
||||
$row->setDestinationProperty($this->getKey('bundle'), $bundle);
|
||||
}
|
||||
|
||||
// Stubs might need some required fields filled in.
|
||||
if ($row->isStub()) {
|
||||
$this->processStubRow($row);
|
||||
|
|
|
@ -143,7 +143,7 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
// Set up some defaults based on the source configuration.
|
||||
$this->cacheCounts = !empty($configuration['cache_counts']);
|
||||
$this->skipCount = !empty($configuration['skip_count']);
|
||||
$this->cacheKey = !empty($configuration['cache_key']) ? !empty($configuration['cache_key']) : NULL;
|
||||
$this->cacheKey = !empty($configuration['cache_key']) ? $configuration['cache_key'] : NULL;
|
||||
$this->trackChanges = !empty($configuration['track_changes']) ? $configuration['track_changes'] : FALSE;
|
||||
$this->idMap = $this->migration->getIdMap();
|
||||
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
id: node_template
|
||||
label: Template test - node
|
||||
migration_tags:
|
||||
- Template Test
|
||||
source:
|
||||
plugin: empty
|
||||
process:
|
||||
src: barfoo
|
||||
destination:
|
||||
plugin: entity:node
|
|
@ -1,10 +0,0 @@
|
|||
id: other_template
|
||||
label: Template with a different tag
|
||||
migration_tags:
|
||||
- Different Template Test
|
||||
source:
|
||||
plugin: empty
|
||||
process:
|
||||
src: raboof
|
||||
destination:
|
||||
plugin: entity:user
|
|
@ -1,10 +0,0 @@
|
|||
id: url_template
|
||||
label: Template test - URL
|
||||
migration_tags:
|
||||
- Template Test
|
||||
source:
|
||||
plugin: empty
|
||||
process:
|
||||
src: foobar
|
||||
destination:
|
||||
plugin: url_alias
|
|
@ -1,5 +0,0 @@
|
|||
name: 'Migration template test'
|
||||
type: module
|
||||
package: Testing
|
||||
version: VERSION
|
||||
core: 8.x
|
155
core/modules/migrate/tests/src/Kernel/MigrateBundleTest.php
Normal file
155
core/modules/migrate/tests/src/Kernel/MigrateBundleTest.php
Normal file
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\migrate\Kernel;
|
||||
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
||||
/**
|
||||
* Tests setting of bundles on content entity migrations.
|
||||
*
|
||||
* @group migrate
|
||||
*/
|
||||
class MigrateBundleTest extends MigrateTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['taxonomy', 'text'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('taxonomy_vocabulary');
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->installConfig(['taxonomy']);
|
||||
// Set up two vocabularies (taxonomy bundles).
|
||||
Vocabulary::create(['vid' => 'tags', 'name' => 'Tags']);
|
||||
Vocabulary::create(['vid' => 'categories', 'name' => 'Categories']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests setting the bundle in the destination.
|
||||
*/
|
||||
public function testDestinationBundle() {
|
||||
$term_data_rows = [
|
||||
['id' => 1, 'name' => 'Category 1'],
|
||||
];
|
||||
$ids = ['id' => ['type' => 'integer']];
|
||||
$definition = [
|
||||
'id' => 'terms',
|
||||
'migration_tags' => ['Bundle test'],
|
||||
'source' => [
|
||||
'plugin' => 'embedded_data',
|
||||
'data_rows' => $term_data_rows,
|
||||
'ids' => $ids,
|
||||
],
|
||||
'process' => [
|
||||
'tid' => 'id',
|
||||
'name' => 'name',
|
||||
],
|
||||
'destination' => [
|
||||
'plugin' => 'entity:taxonomy_term',
|
||||
'default_bundle' => 'categories',
|
||||
],
|
||||
'migration_dependencies' => [],
|
||||
];
|
||||
|
||||
$term_migration = \Drupal::service('plugin.manager.migration')->createStubMigration($definition);
|
||||
|
||||
// Import and validate the term entity was created with the correct bundle.
|
||||
$term_executable = new MigrateExecutable($term_migration, $this);
|
||||
$term_executable->import();
|
||||
/** @var Term $term */
|
||||
$term = Term::load(1);
|
||||
$this->assertEquals($term->bundle(), 'categories');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests setting the bundle in the process pipeline.
|
||||
*/
|
||||
public function testProcessBundle() {
|
||||
$term_data_rows = [
|
||||
['id' => 1, 'vocab' => 'categories', 'name' => 'Category 1'],
|
||||
['id' => 2, 'vocab' => 'tags', 'name' => 'Tag 1'],
|
||||
];
|
||||
$ids = ['id' => ['type' => 'integer']];
|
||||
$definition = [
|
||||
'id' => 'terms',
|
||||
'migration_tags' => ['Bundle test'],
|
||||
'source' => [
|
||||
'plugin' => 'embedded_data',
|
||||
'data_rows' => $term_data_rows,
|
||||
'ids' => $ids,
|
||||
],
|
||||
'process' => [
|
||||
'tid' => 'id',
|
||||
'vid' => 'vocab',
|
||||
'name' => 'name',
|
||||
],
|
||||
'destination' => [
|
||||
'plugin' => 'entity:taxonomy_term',
|
||||
],
|
||||
'migration_dependencies' => [],
|
||||
];
|
||||
|
||||
$term_migration = \Drupal::service('plugin.manager.migration')->createStubMigration($definition);
|
||||
|
||||
// Import and validate the term entities were created with the correct bundle.
|
||||
$term_executable = new MigrateExecutable($term_migration, $this);
|
||||
$term_executable->import();
|
||||
/** @var Term $term */
|
||||
$term = Term::load(1);
|
||||
$this->assertEquals($term->bundle(), 'categories');
|
||||
$term = Term::load(2);
|
||||
$this->assertEquals($term->bundle(), 'tags');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests setting bundles both in process and destination.
|
||||
*/
|
||||
public function testMixedBundles() {
|
||||
$term_data_rows = [
|
||||
['id' => 1, 'vocab' => 'categories', 'name' => 'Category 1'],
|
||||
['id' => 2, 'name' => 'Tag 1'],
|
||||
];
|
||||
$ids = ['id' => ['type' => 'integer']];
|
||||
$definition = [
|
||||
'id' => 'terms',
|
||||
'migration_tags' => ['Bundle test'],
|
||||
'source' => [
|
||||
'plugin' => 'embedded_data',
|
||||
'data_rows' => $term_data_rows,
|
||||
'ids' => $ids,
|
||||
],
|
||||
'process' => [
|
||||
'tid' => 'id',
|
||||
'vid' => 'vocab',
|
||||
'name' => 'name',
|
||||
],
|
||||
'destination' => [
|
||||
'plugin' => 'entity:taxonomy_term',
|
||||
// When no vocab is provided, the destination bundle is applied.
|
||||
'default_bundle' => 'tags',
|
||||
],
|
||||
'migration_dependencies' => [],
|
||||
];
|
||||
|
||||
$term_migration = \Drupal::service('plugin.manager.migration')->createStubMigration($definition);
|
||||
|
||||
// Import and validate the term entities were created with the correct bundle.
|
||||
$term_executable = new MigrateExecutable($term_migration, $this);
|
||||
$term_executable->import();
|
||||
/** @var Term $term */
|
||||
$term = Term::load(1);
|
||||
$this->assertEquals($term->bundle(), 'categories');
|
||||
$term = Term::load(2);
|
||||
$this->assertEquals($term->bundle(), 'tags');
|
||||
}
|
||||
|
||||
}
|
|
@ -27,4 +27,41 @@ class MigrationTest extends KernelTestBase {
|
|||
$this->assertEquals([], $migration->getProcessPlugins([]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests Migration::getMigrationDependencies()
|
||||
*
|
||||
* @covers ::getMigrationDependencies
|
||||
*/
|
||||
public function testGetMigrationDependencies() {
|
||||
$migration = \Drupal::service('plugin.manager.migration')->createStubMigration([
|
||||
'migration_dependencies' => NULL
|
||||
]);
|
||||
$this->assertNotEmpty($migration->getMigrationDependencies(), 'Migration dependencies is not empty');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests Migration::getDestinationIds()
|
||||
*
|
||||
* @covers ::getDestinationIds
|
||||
*/
|
||||
public function testGetDestinationIds() {
|
||||
$migration = \Drupal::service('plugin.manager.migration')->createStubMigration(['destinationIds' => ['foo' => 'bar']]);
|
||||
$destination_ids = $migration->getDestinationIds();
|
||||
$this->assertNotEmpty($destination_ids, 'Destination ids are not empty');
|
||||
$this->assertEquals(['foo' => 'bar'], $destination_ids, 'Destination ids match the expected values.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests Migration::getTrackLastImported()
|
||||
*
|
||||
* @covers ::getTrackLastImported
|
||||
* @covers ::isTrackLastImported
|
||||
*/
|
||||
public function testGetTrackLastImported() {
|
||||
$migration = \Drupal::service('plugin.manager.migration')->createStubMigration([]);
|
||||
$migration->setTrackLastImported(TRUE);
|
||||
$this->assertEquals(TRUE, $migration->getTrackLastImported());
|
||||
$this->assertEquals(TRUE, $migration->isTrackLastImported());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -170,6 +170,25 @@ class MigrateSourceTest extends MigrateTestCase {
|
|||
$this->assertEquals(-1, $source->count());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the key can be set for the count cache.
|
||||
*
|
||||
* @covers ::count
|
||||
*/
|
||||
public function testCountCacheKey() {
|
||||
// Mock the cache to validate set() receives appropriate arguments.
|
||||
$container = new ContainerBuilder();
|
||||
$cache = $this->getMock(CacheBackendInterface::class);
|
||||
$cache->expects($this->any())->method('set')
|
||||
->with('test_key', $this->isType('int'), $this->isType('int'));
|
||||
$container->set('cache.migrate', $cache);
|
||||
\Drupal::setContainer($container);
|
||||
|
||||
// Test caching the count with a configured key works.
|
||||
$source = $this->getSource(['cache_counts' => TRUE, 'cache_key' => 'test_key']);
|
||||
$this->assertEquals(1, $source->count());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that we don't get a row if prepareRow() is false.
|
||||
*/
|
||||
|
|
|
@ -199,9 +199,11 @@ abstract class MigrateTestCase extends UnitTestCase {
|
|||
*/
|
||||
protected function retrievalAssertHelper($expected_value, $actual_value, $message) {
|
||||
if (is_array($expected_value)) {
|
||||
foreach ($expected_value as $k => $v) {
|
||||
$this->retrievalAssertHelper($v, $actual_value[$k], $message . '[' . $k . ']');
|
||||
// If the expected and actual values are empty, no need to array compare.
|
||||
if (empty($expected_value && $actual_value)) {
|
||||
return;
|
||||
}
|
||||
$this->assertArrayEquals($expected_value, $actual_value, $message);
|
||||
}
|
||||
else {
|
||||
$this->assertSame((string) $expected_value, (string) $actual_value, $message);
|
||||
|
|
Reference in a new issue