summaryrefslogtreecommitdiffstats
path: root/core/modules/migrate_drupal
diff options
context:
space:
mode:
authorNathaniel Catchpole2018-02-07 15:23:02 (GMT)
committerNathaniel Catchpole2018-02-07 15:23:02 (GMT)
commitef5b216cf1750a8ace5be36071d008718b82713b (patch)
treea1bf433cb873ef571219f9fcd4e7eaea614da329 /core/modules/migrate_drupal
parentd1932299de44863ee167da895180e6fbe6d5fd1f (diff)
Issue #2935951 by heddn, maxocub, quietone, Jo Fitzgerald, phenaproxima, alexpott, larowlan: Copy migrate source plugin from migrate_drupal_d8 into migrate_drupal
Diffstat (limited to 'core/modules/migrate_drupal')
-rw-r--r--core/modules/migrate_drupal/src/Plugin/migrate/source/ContentEntity.php294
-rw-r--r--core/modules/migrate_drupal/src/Plugin/migrate/source/ContentEntityDeriver.php60
-rw-r--r--core/modules/migrate_drupal/tests/src/Kernel/Plugin/migrate/source/ContentEntityTest.php444
3 files changed, 798 insertions, 0 deletions
diff --git a/core/modules/migrate_drupal/src/Plugin/migrate/source/ContentEntity.php b/core/modules/migrate_drupal/src/Plugin/migrate/source/ContentEntity.php
new file mode 100644
index 0000000..1219510
--- /dev/null
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/source/ContentEntity.php
@@ -0,0 +1,294 @@
+<?php
+
+namespace Drupal\migrate_drupal\Plugin\migrate\source;
+
+use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
+use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Entity\ContentEntityTypeInterface;
+use Drupal\Core\Entity\EntityFieldManagerInterface;
+use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\migrate\Plugin\migrate\source\SourcePluginBase;
+use Drupal\migrate\Plugin\MigrationInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Source plugin to get content entities from the current version of Drupal.
+ *
+ * This plugin uses the Entity API to export entity data. If the source entity
+ * type has custom field storage fields or computed fields, this class will need
+ * to be extended and the new class will need to load/calculate the values for
+ * those fields.
+ *
+ * Available configuration keys:
+ * - entity_type: The entity type ID of the entities being exported. This is
+ * calculated dynamically by the deriver so it is only needed if the deriver
+ * is not utilized, i.e., a custom source plugin.
+ * - bundle: (optional) If the entity type is bundleable, only return entities
+ * of this bundle.
+ * - include_translations: (optional) Indicates if the entity translations
+ * should be included, defaults to TRUE.
+ *
+ * Examples:
+ *
+ * This will return all nodes, from every bundle and every translation. It does
+ * not return all revisions, just the default one.
+ * @code
+ * source:
+ * plugin: content_entity:node
+ * @endcode
+ *
+ * This will only return nodes of type 'article' in their default language.
+ * @code
+ * source:
+ * plugin: content_entity:node
+ * bundle: article
+ * include_translations: false
+ * @endcode
+ *
+ * @MigrateSource(
+ * id = "content_entity",
+ * source_module = "migrate_drupal",
+ * deriver = "\Drupal\migrate_drupal\Plugin\migrate\source\ContentEntityDeriver",
+ * )
+ */
+class ContentEntity extends SourcePluginBase implements ContainerFactoryPluginInterface {
+
+ /**
+ * The entity type manager.
+ *
+ * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+ */
+ protected $entityTypeManager;
+
+ /**
+ * The entity field manager.
+ *
+ * @var \Drupal\Core\Entity\EntityFieldManagerInterface
+ */
+ protected $entityFieldManager;
+
+ /**
+ * The entity type bundle info service.
+ *
+ * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
+ */
+ protected $entityTypeBundleInfo;
+
+ /**
+ * The entity type definition.
+ *
+ * @var \Drupal\Core\Entity\EntityTypeInterface
+ */
+ protected $entityType;
+
+ /**
+ * The plugin's default configuration.
+ *
+ * @var array
+ */
+ protected $defaultConfiguration = [
+ 'bundle' => NULL,
+ 'include_translations' => TRUE,
+ ];
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info) {
+ if (empty($plugin_definition['entity_type'])) {
+ throw new InvalidPluginDefinitionException($plugin_id, 'Missing required "entity_type" definition.');
+ }
+ $this->entityTypeManager = $entity_type_manager;
+ $this->entityFieldManager = $entity_field_manager;
+ $this->entityTypeBundleInfo = $entity_type_bundle_info;
+ $this->entityType = $this->entityTypeManager->getDefinition($plugin_definition['entity_type']);
+ if (!$this->entityType instanceof ContentEntityTypeInterface) {
+ throw new InvalidPluginDefinitionException($plugin_id, sprintf('The entity type (%s) is not supported. The "content_entity" source plugin only supports content entities.', $plugin_definition['entity_type']));
+ }
+ if (!empty($configuration['bundle'])) {
+ if (!$this->entityType->hasKey('bundle')) {
+ throw new \InvalidArgumentException(sprintf('A bundle was provided but the entity type (%s) is not bundleable.', $plugin_definition['entity_type']));
+ }
+ $bundle_info = array_keys($this->entityTypeBundleInfo->getBundleInfo($this->entityType->id()));
+ if (!in_array($configuration['bundle'], $bundle_info, TRUE)) {
+ throw new \InvalidArgumentException(sprintf('The provided bundle (%s) is not valid for the (%s) entity type.', $configuration['bundle'], $plugin_definition['entity_type']));
+ }
+ }
+ parent::__construct($configuration + $this->defaultConfiguration, $plugin_id, $plugin_definition, $migration);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
+ return new static(
+ $configuration,
+ $plugin_id,
+ $plugin_definition,
+ $migration,
+ $container->get('entity_type.manager'),
+ $container->get('entity_field.manager'),
+ $container->get('entity_type.bundle.info')
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString() {
+ return (string) $this->entityType->getPluralLabel();
+ }
+
+ /**
+ * Initializes the iterator with the source data.
+ *
+ * @return \Generator
+ * A data generator for this source.
+ */
+ protected function initializeIterator() {
+ $ids = $this->query()->execute();
+ return $this->yieldEntities($ids);
+ }
+
+ /**
+ * Loads and yields entities, one at a time.
+ *
+ * @param array $ids
+ * The entity IDs.
+ *
+ * @return \Generator
+ * An iterable of the loaded entities.
+ */
+ protected function yieldEntities(array $ids) {
+ $storage = $this->entityTypeManager
+ ->getStorage($this->entityType->id());
+ foreach ($ids as $id) {
+ /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
+ $entity = $storage->load($id);
+ yield $this->toArray($entity);
+ if ($this->configuration['include_translations']) {
+ foreach ($entity->getTranslationLanguages(FALSE) as $language) {
+ yield $this->toArray($entity->getTranslation($language->getId()));
+ }
+ }
+ }
+ }
+
+ /**
+ * Converts an entity to an array.
+ *
+ * Makes all IDs into flat values. All other values are returned as per
+ * $entity->toArray(), which is a nested array.
+ *
+ * @param \Drupal\Core\Entity\ContentEntityInterface $entity
+ * The entity to convert.
+ *
+ * @return array
+ * The entity, represented as an array.
+ */
+ protected function toArray(ContentEntityInterface $entity) {
+ $return = $entity->toArray();
+ // This is necessary because the IDs must be flat. They cannot be nested for
+ // the ID map.
+ foreach (array_keys($this->getIds()) as $id) {
+ /** @var \Drupal\Core\TypedData\Plugin\DataType\ItemList $value */
+ $value = $entity->get($id);
+ // Force the IDs on top of the previous values.
+ $return[$id] = $value->first()->getString();
+ }
+ return $return;
+ }
+
+ /**
+ * Query to retrieve the entities.
+ *
+ * @return \Drupal\Core\Entity\Query\QueryInterface
+ * The query.
+ */
+ public function query() {
+ $query = $this->entityTypeManager
+ ->getStorage($this->entityType->id())
+ ->getQuery()
+ ->accessCheck(FALSE);
+ if (!empty($this->configuration['bundle'])) {
+ $query->condition($this->entityType->getKey('bundle'), $this->configuration['bundle']);
+ }
+ return $query;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function count($refresh = FALSE) {
+ // If no translations are included, then a simple query is possible.
+ if (!$this->configuration['include_translations']) {
+ return parent::count($refresh);
+ }
+ // @TODO: Determine a better way to retrieve a valid count for translations.
+ // https://www.drupal.org/project/drupal/issues/2937166
+ return -1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function doCount() {
+ return $this->query()->count()->execute();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function fields() {
+ // Retrieving fields from a non-fieldable content entity will throw a
+ // LogicException. Return an empty list of fields instead.
+ if (!$this->entityType->entityClassImplements('Drupal\Core\Entity\FieldableEntityInterface')) {
+ return [];
+ }
+ $field_definitions = $this->entityFieldManager->getBaseFieldDefinitions($this->entityType->id());
+ if (!empty($this->configuration['bundle'])) {
+ $field_definitions += $this->entityFieldManager->getFieldDefinitions($this->entityType->id(), $this->configuration['bundle']);
+ }
+ $fields = array_map(function ($definition) {
+ return (string) $definition->getLabel();
+ }, $field_definitions);
+ return $fields;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getIds() {
+ $id_key = $this->entityType->getKey('id');
+ $ids[$id_key] = $this->getDefinitionFromEntity($id_key);
+ if ($this->entityType->isTranslatable()) {
+ $langcode_key = $this->entityType->getKey('langcode');
+ $ids[$langcode_key] = $this->getDefinitionFromEntity($langcode_key);
+ }
+ return $ids;
+ }
+
+ /**
+ * Gets the field definition from a specific entity base field.
+ *
+ * @param string $key
+ * The field ID key.
+ *
+ * @return array
+ * An associative array with a structure that contains the field type, keyed
+ * as 'type', together with field storage settings as they are returned by
+ * FieldStorageDefinitionInterface::getSettings().
+ *
+ * @see \Drupal\migrate\Plugin\migrate\destination\EntityContentBase::getDefinitionFromEntity()
+ */
+ protected function getDefinitionFromEntity($key) {
+ /** @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */
+ $field_definition = $this->entityFieldManager->getBaseFieldDefinitions($this->entityType->id())[$key];
+ return [
+ 'type' => $field_definition->getType(),
+ ] + $field_definition->getSettings();
+ }
+
+}
diff --git a/core/modules/migrate_drupal/src/Plugin/migrate/source/ContentEntityDeriver.php b/core/modules/migrate_drupal/src/Plugin/migrate/source/ContentEntityDeriver.php
new file mode 100644
index 0000000..2740441
--- /dev/null
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/source/ContentEntityDeriver.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Drupal\migrate_drupal\Plugin\migrate\source;
+
+use Drupal\Component\Plugin\Derivative\DeriverBase;
+use Drupal\Core\Entity\ContentEntityTypeInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Deriver for content entity source plugins.
+ */
+class ContentEntityDeriver extends DeriverBase implements ContainerDeriverInterface {
+
+ /**
+ * The entity type manager.
+ *
+ * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+ */
+ protected $entityTypeManager;
+
+ /**
+ * Constructs a new ContentEntityDeriver.
+ *
+ * @param string $base_plugin_id
+ * The base plugin ID.
+ * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
+ * The entity type manager.
+ */
+ public function __construct($base_plugin_id, EntityTypeManagerInterface $entityTypeManager) {
+ $this->entityTypeManager = $entityTypeManager;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container, $base_plugin_id) {
+ return new static(
+ $base_plugin_id,
+ $container->get('entity_type.manager')
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDerivativeDefinitions($base_plugin_definition) {
+ $this->derivatives = [];
+ foreach ($this->entityTypeManager->getDefinitions() as $id => $definition) {
+ if ($definition instanceof ContentEntityTypeInterface) {
+ $this->derivatives[$id] = $base_plugin_definition;
+ // Provide entity_type so the source can be used apart from a deriver.
+ $this->derivatives[$id]['entity_type'] = $id;
+ }
+ }
+ return parent::getDerivativeDefinitions($base_plugin_definition);
+ }
+
+}
diff --git a/core/modules/migrate_drupal/tests/src/Kernel/Plugin/migrate/source/ContentEntityTest.php b/core/modules/migrate_drupal/tests/src/Kernel/Plugin/migrate/source/ContentEntityTest.php
new file mode 100644
index 0000000..72372af
--- /dev/null
+++ b/core/modules/migrate_drupal/tests/src/Kernel/Plugin/migrate/source/ContentEntityTest.php
@@ -0,0 +1,444 @@
+<?php
+
+namespace Drupal\Tests\migrate_drupal\Kernel\Plugin\migrate\source;
+
+use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Language\LanguageInterface;
+use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
+use Drupal\file\Entity\File;
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\media\Entity\Media;
+use Drupal\migrate\Plugin\MigrationInterface;
+use Drupal\migrate_drupal\Plugin\migrate\source\ContentEntity;
+use Drupal\node\Entity\Node;
+use Drupal\node\Entity\NodeType;
+use Drupal\taxonomy\Entity\Term;
+use Drupal\taxonomy\Entity\Vocabulary;
+use Drupal\Tests\media\Functional\MediaFunctionalTestCreateMediaTypeTrait;
+use Drupal\user\Entity\User;
+
+/**
+ * Tests the entity content source plugin.
+ *
+ * @group migrate_drupal
+ */
+class ContentEntityTest extends KernelTestBase {
+
+ use EntityReferenceTestTrait;
+ use MediaFunctionalTestCreateMediaTypeTrait;
+
+ /**
+ * {@inheritdoc}
+ */
+ public static $modules = [
+ 'user',
+ 'migrate',
+ 'migrate_drupal',
+ 'system',
+ 'node',
+ 'taxonomy',
+ 'field',
+ 'file',
+ 'image',
+ 'media',
+ 'media_test_source',
+ 'text',
+ 'filter',
+ 'language',
+ 'content_translation',
+ ];
+
+ /**
+ * The bundle used in this test.
+ *
+ * @var string
+ */
+ protected $bundle = 'article';
+
+ /**
+ * The name of the field used in this test.
+ *
+ * @var string
+ */
+ protected $fieldName = 'field_entity_reference';
+
+ /**
+ * The vocabulary ID.
+ *
+ * @var string
+ */
+ protected $vocabulary = 'fruit';
+
+ /**
+ * The test user.
+ *
+ * @var \Drupal\user\Entity\User
+ */
+ protected $user;
+
+ /**
+ * The migration plugin manager.
+ *
+ * @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
+ */
+ protected $migrationPluginManager;
+
+ /**
+ * The source plugin manager.
+ *
+ * @var \Drupal\migrate\Plugin\MigrateSourcePluginManager
+ */
+ protected $sourcePluginManager;
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp();
+ $this->installEntitySchema('node');
+ $this->installEntitySchema('file');
+ $this->installEntitySchema('media');
+ $this->installEntitySchema('taxonomy_term');
+ $this->installEntitySchema('taxonomy_vocabulary');
+ $this->installEntitySchema('user');
+ $this->installSchema('system', ['sequences']);
+ $this->installSchema('user', 'users_data');
+ $this->installSchema('file', 'file_usage');
+ $this->installSchema('node', ['node_access']);
+ $this->installConfig($this->modules);
+
+ ConfigurableLanguage::createFromLangcode('fr')->save();
+
+ // Create article content type.
+ $node_type = NodeType::create(['type' => $this->bundle, 'name' => 'Article']);
+ $node_type->save();
+
+ // Create a vocabulary.
+ $vocabulary = Vocabulary::create([
+ 'name' => $this->vocabulary,
+ 'description' => $this->vocabulary,
+ 'vid' => $this->vocabulary,
+ 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
+ ]);
+ $vocabulary->save();
+
+ // Create a term reference field on node.
+ $this->createEntityReferenceField(
+ 'node',
+ $this->bundle,
+ $this->fieldName,
+ 'Term reference',
+ 'taxonomy_term',
+ 'default',
+ ['target_bundles' => [$this->vocabulary]],
+ FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED
+ );
+ // Create a term reference field on user.
+ $this->createEntityReferenceField(
+ 'user',
+ 'user',
+ $this->fieldName,
+ 'Term reference',
+ 'taxonomy_term',
+ 'default',
+ ['target_bundles' => [$this->vocabulary]],
+ FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED
+ );
+
+ // Create some data.
+ $this->user = User::create([
+ 'name' => 'user123',
+ 'uid' => 1,
+ 'mail' => 'example@example.com',
+ ]);
+ $this->user->save();
+
+ $term = Term::create([
+ 'vid' => $this->vocabulary,
+ 'name' => 'Apples',
+ 'uid' => $this->user->id(),
+ ]);
+ $term->save();
+ $this->user->set($this->fieldName, $term->id());
+ $this->user->save();
+ $node = Node::create([
+ 'type' => $this->bundle,
+ 'title' => 'Apples',
+ $this->fieldName => $term->id(),
+ 'uid' => $this->user->id(),
+ ]);
+ $node->save();
+ $node->addTranslation('fr', [
+ 'title' => 'Pommes',
+ $this->fieldName => $term->id(),
+ ])->save();
+
+ $this->sourcePluginManager = $this->container->get('plugin.manager.migrate.source');
+ $this->migrationPluginManager = $this->container->get('plugin.manager.migration');
+ }
+
+ /**
+ * Tests the constructor for missing entity_type.
+ */
+ public function testConstructorEntityTypeMissing() {
+ $migration = $this->prophesize(MigrationInterface::class)->reveal();
+ $configuration = [];
+ $plugin_definition = [
+ 'entity_type' => '',
+ ];
+ $this->setExpectedException(InvalidPluginDefinitionException::class, 'Missing required "entity_type" definition.');
+ ContentEntity::create($this->container, $configuration, 'content_entity', $plugin_definition, $migration);
+ }
+
+ /**
+ * Tests the constructor for non content entity.
+ */
+ public function testConstructorNonContentEntity() {
+ $migration = $this->prophesize(MigrationInterface::class)->reveal();
+ $configuration = [];
+ $plugin_definition = [
+ 'entity_type' => 'node_type',
+ ];
+ $this->setExpectedException(InvalidPluginDefinitionException::class, 'The entity type (node_type) is not supported. The "content_entity" source plugin only supports content entities.');
+ ContentEntity::create($this->container, $configuration, 'content_entity:node_type', $plugin_definition, $migration);
+ }
+
+ /**
+ * Tests the constructor for not bundleable entity.
+ */
+ public function testConstructorNotBundable() {
+ $migration = $this->prophesize(MigrationInterface::class)->reveal();
+ $configuration = [
+ 'bundle' => 'foo',
+ ];
+ $plugin_definition = [
+ 'entity_type' => 'user',
+ ];
+ $this->setExpectedException(\InvalidArgumentException::class, 'A bundle was provided but the entity type (user) is not bundleable');
+ ContentEntity::create($this->container, $configuration, 'content_entity:user', $plugin_definition, $migration);
+ }
+
+ /**
+ * Tests the constructor for invalid entity bundle.
+ */
+ public function testConstructorInvalidBundle() {
+ $migration = $this->prophesize(MigrationInterface::class)->reveal();
+ $configuration = [
+ 'bundle' => 'foo',
+ ];
+ $plugin_definition = [
+ 'entity_type' => 'node',
+ ];
+ $this->setExpectedException(\InvalidArgumentException::class, 'The provided bundle (foo) is not valid for the (node) entity type.');
+ ContentEntity::create($this->container, $configuration, 'content_entity:node', $plugin_definition, $migration);
+ }
+
+ /**
+ * Tests user source plugin.
+ */
+ public function testUserSource() {
+ $configuration = [
+ 'include_translations' => FALSE,
+ ];
+ $migration = $this->migrationPluginManager->createStubMigration($this->migrationDefinition('content_entity:user'));
+ $user_source = $this->sourcePluginManager->createInstance('content_entity:user', $configuration, $migration);
+ $this->assertSame('user entities', $user_source->__toString());
+ $this->assertEquals(1, $user_source->count());
+ $ids = $user_source->getIds();
+ $this->assertArrayHasKey('langcode', $ids);
+ $this->assertArrayHasKey('uid', $ids);
+ $fields = $user_source->fields();
+ $this->assertArrayHasKey('name', $fields);
+ $this->assertArrayHasKey('pass', $fields);
+ $this->assertArrayHasKey('mail', $fields);
+ $this->assertArrayHasKey('uid', $fields);
+ $this->assertArrayHasKey('roles', $fields);
+ $user_source->rewind();
+ $values = $user_source->current()->getSource();
+ $this->assertEquals('example@example.com', $values['mail'][0]['value']);
+ $this->assertEquals('user123', $values['name'][0]['value']);
+ $this->assertEquals(1, $values['uid']);
+ $this->assertEquals(1, $values['field_entity_reference'][0]['target_id']);
+ }
+
+ /**
+ * Tests file source plugin.
+ */
+ public function testFileSource() {
+ $file = File::create([
+ 'filename' => 'foo.txt',
+ 'uid' => $this->user->id(),
+ 'uri' => 'public://foo.txt',
+ ]);
+ $file->save();
+
+ $configuration = [
+ 'include_translations' => FALSE,
+ ];
+ $migration = $this->migrationPluginManager->createStubMigration($this->migrationDefinition('content_entity:file'));
+ $file_source = $this->sourcePluginManager->createInstance('content_entity:file', $configuration, $migration);
+ $this->assertSame('file entities', $file_source->__toString());
+ $this->assertEquals(1, $file_source->count());
+ $ids = $file_source->getIds();
+ $this->assertArrayHasKey('fid', $ids);
+ $fields = $file_source->fields();
+ $this->assertArrayHasKey('fid', $fields);
+ $this->assertArrayHasKey('filemime', $fields);
+ $this->assertArrayHasKey('filename', $fields);
+ $this->assertArrayHasKey('uid', $fields);
+ $this->assertArrayHasKey('uri', $fields);
+ $file_source->rewind();
+ $values = $file_source->current()->getSource();
+ $this->assertEquals('text/plain', $values['filemime'][0]['value']);
+ $this->assertEquals('public://foo.txt', $values['uri'][0]['value']);
+ $this->assertEquals('foo.txt', $values['filename'][0]['value']);
+ $this->assertEquals(1, $values['fid']);
+ }
+
+ /**
+ * Tests node source plugin.
+ */
+ public function testNodeSource() {
+ $migration = $this->migrationPluginManager->createStubMigration($this->migrationDefinition('content_entity:node'));
+ $node_source = $this->sourcePluginManager->createInstance('content_entity:node', ['bundle' => $this->bundle], $migration);
+ $this->assertSame('content items', $node_source->__toString());
+ $ids = $node_source->getIds();
+ $this->assertArrayHasKey('langcode', $ids);
+ $this->assertArrayHasKey('nid', $ids);
+ $fields = $node_source->fields();
+ $this->assertArrayHasKey('nid', $fields);
+ $this->assertArrayHasKey('vid', $fields);
+ $this->assertArrayHasKey('title', $fields);
+ $this->assertArrayHasKey('uid', $fields);
+ $this->assertArrayHasKey('sticky', $fields);
+ $node_source->rewind();
+ $values = $node_source->current()->getSource();
+ $this->assertEquals($this->bundle, $values['type'][0]['target_id']);
+ $this->assertEquals(1, $values['nid']);
+ $this->assertEquals('en', $values['langcode']);
+ $this->assertEquals(1, $values['status'][0]['value']);
+ $this->assertEquals('Apples', $values['title'][0]['value']);
+ $this->assertEquals(1, $values['default_langcode'][0]['value']);
+ $this->assertEquals(1, $values['field_entity_reference'][0]['target_id']);
+ $node_source->next();
+ $values = $node_source->current()->getSource();
+ $this->assertEquals($this->bundle, $values['type'][0]['target_id']);
+ $this->assertEquals(1, $values['nid']);
+ $this->assertEquals('fr', $values['langcode']);
+ $this->assertEquals(1, $values['status'][0]['value']);
+ $this->assertEquals('Pommes', $values['title'][0]['value']);
+ $this->assertEquals(0, $values['default_langcode'][0]['value']);
+ $this->assertEquals(1, $values['field_entity_reference'][0]['target_id']);
+ }
+
+ /**
+ * Tests media source plugin.
+ */
+ public function testMediaSource() {
+ $values = [
+ 'id' => 'image',
+ 'bundle' => 'image',
+ 'label' => 'Image',
+ 'source' => 'test',
+ 'new_revision' => FALSE,
+ ];
+ $media_type = $this->createMediaType($values);
+ $media = Media::create([
+ 'name' => 'Foo media',
+ 'uid' => $this->user->id(),
+ 'bundle' => $media_type->id(),
+ ]);
+ $media->save();
+
+ $configuration = [
+ 'include_translations' => FALSE,
+ 'bundle' => 'image',
+ ];
+ $migration = $this->migrationPluginManager->createStubMigration($this->migrationDefinition('content_entity:media'));
+ $media_source = $this->sourcePluginManager->createInstance('content_entity:media', $configuration, $migration);
+ $this->assertSame('media items', $media_source->__toString());
+ $this->assertEquals(1, $media_source->count());
+ $ids = $media_source->getIds();
+ $this->assertArrayHasKey('langcode', $ids);
+ $this->assertArrayHasKey('mid', $ids);
+ $fields = $media_source->fields();
+ $this->assertArrayHasKey('bundle', $fields);
+ $this->assertArrayHasKey('mid', $fields);
+ $this->assertArrayHasKey('name', $fields);
+ $this->assertArrayHasKey('status', $fields);
+ $media_source->rewind();
+ $values = $media_source->current()->getSource();
+ $this->assertEquals(1, $values['mid']);
+ $this->assertEquals('Foo media', $values['name'][0]['value']);
+ $this->assertEquals('Foo media', $values['thumbnail'][0]['title']);
+ $this->assertEquals(1, $values['uid'][0]['target_id']);
+ $this->assertEquals('image', $values['bundle'][0]['target_id']);
+ }
+
+ /**
+ * Tests term source plugin.
+ */
+ public function testTermSource() {
+ $term2 = Term::create([
+ 'vid' => $this->vocabulary,
+ 'name' => 'Granny Smith',
+ 'uid' => $this->user->id(),
+ 'parent' => 1,
+ ]);
+ $term2->save();
+
+ $configuration = [
+ 'include_translations' => FALSE,
+ 'bundle' => $this->vocabulary,
+ ];
+ $migration = $this->migrationPluginManager->createStubMigration($this->migrationDefinition('content_entity:taxonomy_term'));
+ $term_source = $this->sourcePluginManager->createInstance('content_entity:taxonomy_term', $configuration, $migration);
+ $this->assertSame('taxonomy term entities', $term_source->__toString());
+ $this->assertEquals(2, $term_source->count());
+ $ids = $term_source->getIds();
+ $this->assertArrayHasKey('langcode', $ids);
+ $this->assertArrayHasKey('tid', $ids);
+ $fields = $term_source->fields();
+ $this->assertArrayHasKey('vid', $fields);
+ $this->assertArrayHasKey('tid', $fields);
+ $this->assertArrayHasKey('name', $fields);
+ $term_source->rewind();
+ $values = $term_source->current()->getSource();
+ $this->assertEquals($this->vocabulary, $values['vid'][0]['target_id']);
+ $this->assertEquals(1, $values['tid']);
+ // @TODO: Add test coverage for parent in
+ // https://www.drupal.org/project/drupal/issues/2940198
+ $this->assertEquals('Apples', $values['name'][0]['value']);
+ $term_source->next();
+ $values = $term_source->current()->getSource();
+ $this->assertEquals($this->vocabulary, $values['vid'][0]['target_id']);
+ $this->assertEquals(2, $values['tid']);
+ // @TODO: Add test coverage for parent in
+ // https://www.drupal.org/project/drupal/issues/2940198
+ $this->assertEquals('Granny Smith', $values['name'][0]['value']);
+ }
+
+ /**
+ * Get a migration definition.
+ *
+ * @param string $plugin_id
+ * The plugin id.
+ *
+ * @return array
+ * The definition.
+ */
+ protected function migrationDefinition($plugin_id) {
+ return [
+ 'source' => [
+ 'plugin' => $plugin_id,
+ ],
+ 'process' => [],
+ 'destination' => [
+ 'plugin' => 'null',
+ ],
+ ];
+ }
+
+}