diff --git a/src/Plugin/Derivative/MigrateEntityReferenceRevisions.php b/src/Plugin/Derivative/MigrateEntityReferenceRevisions.php index 2b8ae69..bb7d0c2 100644 --- a/src/Plugin/Derivative/MigrateEntityReferenceRevisions.php +++ b/src/Plugin/Derivative/MigrateEntityReferenceRevisions.php @@ -7,7 +7,6 @@ /** * Class MigrateEntityReferenceRevisions - * @package Drupal\entity_reference_revisions\Plugin\Derivative */ class MigrateEntityReferenceRevisions extends MigrateEntityRevision { @@ -17,12 +16,12 @@ class MigrateEntityReferenceRevisions extends MigrateEntityRevision { public function getDerivativeDefinitions($basePluginDefinition) { foreach ($this->entityDefinitions as $entityType => $entityInfo) { if ($entityInfo->getKey('revision')) { - $this->derivatives[$entityType] = array( + $this->derivatives[$entityType] = [ 'id' => "entity_reference_revisions:$entityType", 'class' => EntityReferenceRevisions::class, 'requirements_met' => 1, 'provider' => $entityInfo->getProvider(), - ); + ]; } } return $this->derivatives; diff --git a/tests/src/Kernel/Plugin/migrate/destination/EntityReferenceRevisionsDestinationTest.php b/tests/src/Kernel/Plugin/migrate/destination/EntityReferenceRevisionsDestinationTest.php index c0f8b4d..cb2be0e 100644 --- a/tests/src/Kernel/Plugin/migrate/destination/EntityReferenceRevisionsDestinationTest.php +++ b/tests/src/Kernel/Plugin/migrate/destination/EntityReferenceRevisionsDestinationTest.php @@ -4,15 +4,16 @@ use Drupal\Core\Entity\EntityStorageBase; use Drupal\entity_reference_revisions\Plugin\migrate\destination\EntityReferenceRevisions; +use Drupal\field\Entity\FieldConfig; +use Drupal\field\Entity\FieldStorageConfig; use Drupal\KernelTests\KernelTestBase; use Drupal\migrate\MigrateExecutable; use Drupal\migrate\MigrateMessageInterface; use Drupal\migrate\Plugin\Migration; -use Drupal\migrate\Plugin\MigrationPluginManager; -use Drupal\migrate\Plugin\MigrateDestinationPluginManager; +use Drupal\node\Entity\NodeType; /** - * Tests the migration plugin. + * Tests the migration destination plugin. * * @coversDefaultClass \Drupal\entity_reference_revisions\Plugin\migrate\destination\EntityReferenceRevisions * @group entity_reference_revisions @@ -20,15 +21,22 @@ class EntityReferenceRevisionsDestinationTest extends KernelTestBase implements MigrateMessageInterface { /** + * @var \Drupal\migrate\Plugin\MigrationPluginManager $migrationManager + * + * The migration plugin manager. + */ + protected $migrationPluginManager; + + /** * {@inheritdoc} */ public static $modules = [ 'migrate', - 'err_migration_test', 'entity_reference_revisions', 'entity_composite_relationship_test', 'user', 'system', + 'text', ]; /** @@ -39,19 +47,20 @@ protected function setUp() { $this->installEntitySchema('entity_test_composite'); $this->installSchema('system', ['sequences']); $this->installConfig($this->modules); + + $this->migrationPluginManager = \Drupal::service('plugin.manager.migration'); } /** * Tests get entity type id. * + * @dataProvider getEntityTypeIdDataProvider + * * @covers ::getEntityTypeId */ - public function testGetEntityTypeId() { - /** @var MigrationPluginManager $migrationManager */ - $migrationManager = \Drupal::service('plugin.manager.migration'); - $definition = $migrationManager->getDefinition('err_migration_test'); + public function testGetEntityTypeId(array $definition, $expected) { /** @var Migration $migration */ - $migration = $migrationManager->createStubMigration($definition); + $migration = $this->migrationPluginManager->createStubMigration($definition); /** @var EntityReferenceRevisions $destination */ $destination = $migration->getDestinationPlugin(); @@ -59,23 +68,34 @@ public function testGetEntityTypeId() { $storage = $this->readAttribute($destination, 'storage'); $actual = $this->readAttribute($storage, 'entityTypeId'); - $expected = 'entity_test_composite'; $this->assertEquals($expected, $actual); } /** + * Provides multiple migration definitions for "getEntityTypeId" test. + */ + public function getEntityTypeIdDataProvider() { + $datas = $this->getEntityDataProvider(); + + foreach ($datas as &$data) { + $data['expected'] = 'entity_test_composite'; + } + + return $datas; + } + + /** * Tests get entity. * + * @dataProvider getEntityDataProvider + * * @covers ::getEntity * @covers ::rollback * @covers ::rollbackNonTranslation */ - public function testGetEntity() { - /** @var MigrationPluginManager $migrationManager */ - $migrationManager = \Drupal::service('plugin.manager.migration'); - $definition = $migrationManager->getDefinition('err_migration_test'); + public function testGetEntity(array $definition, array $expected) { /** @var Migration $migration */ - $migration = $migrationManager->createStubMigration($definition); + $migration = $this->migrationPluginManager->createStubMigration($definition); $migrationExecutable = (new MigrateExecutable($migration, $this)); /** @var EntityStorageBase $storage */ $storage = $this->readAttribute($migration->getDestinationPlugin(), 'storage'); @@ -83,16 +103,408 @@ public function testGetEntity() { for ($i = 0; $i < 2; $i++) { $migrationExecutable->import(); $migration->getIdMap()->prepareUpdate(); - $entity = $storage->loadRevision(1); - $this->assertEquals('content item 1', $entity->label()); - $entity = $storage->loadRevision(2); - $this->assertEquals('content item 2', $entity->label()); + foreach ($expected as $data) { + $entity = $storage->loadRevision($data['id']); + $this->assertEquals($data['label'], $entity->label()); + } } $migrationExecutable->rollback(); - $entity = $storage->loadRevision(1); - $this->assertEmpty($entity); - $entity = $storage->loadRevision(2); - $this->assertEmpty($entity); + foreach ($expected as $data) { + $entity = $storage->loadRevision($data['id']); + $this->assertEmpty($entity); + } + } + + /** + * Provides multiple migration definitions for "getEntity" test. + */ + public function getEntityDataProvider() { + return [ + 'without keys' => [ + 'definition' => [ + 'source' => [ + 'plugin' => 'embedded_data', + 'data_rows' => [ + ['id' => 1, 'name' => 'content item 1a'], + ['id' => 1, 'name' => 'content item 1b'], + ['id' => 2, 'name' => 'content item 2'], + ], + 'ids' => [ + 'id' => ['type' => 'integer'], + 'name' => ['type' => 'text'], + ], + ], + 'process' => [ + 'name' => 'name', + ], + 'destination' => [ + 'plugin' => 'entity_reference_revisions:entity_test_composite', + ], + ], + 'expected' => [ + ['id' => 1, 'label' => 'content item 1a'], + ['id' => 2, 'label' => 'content item 1b'], + ['id' => 3, 'label' => 'content item 2'], + ], + ], + 'with keys' => [ + 'definition' => [ + 'source' => [ + 'plugin' => 'embedded_data', + 'data_rows' => [ + ['id' => 1, 'revision_id' => 1, 'name' => 'content item 1'], + ['id' => 2, 'revision_id' => 2, 'name' => 'content item 2'], + ['id' => 3, 'revision_id' => 3, 'name' => 'content item 3'], + ], + 'ids' => [ + 'id' => ['type' => 'integer'], + 'name' => ['type' => 'text'], + ], + ], + 'process' => [ + 'id' => 'id', + 'revision_id' => 'revision_id', + 'name' => 'name', + ], + 'destination' => [ + 'plugin' => 'entity_reference_revisions:entity_test_composite', + ], + ], + 'expected' => [ + ['id' => 1, 'label' => 'content item 1'], + ['id' => 2, 'label' => 'content item 2'], + ['id' => 3, 'label' => 'content item 3'], + ], + ], + ]; + } + + /** + * Tests multi-value and single-value destination field linkage. + * + * @dataProvider destinationFieldMappingDataProvider + * + * @covers ::getEntity + * @covers ::rollback + * @covers ::rollbackNonTranslation + */ + public function testDestinationFieldMapping(array $datas) { + $this->enableModules(['node', 'field']); + $this->installEntitySchema('node'); + $this->installEntitySchema('user'); + $this->installSchema('node', ['node_access']); + + // Create new content type. + $values = ['type' => 'article', 'name' => 'Article']; + $node_type = NodeType::create($values); + $node_type->save(); + + // Add the field_err_single field to the node type. + $field_storage = FieldStorageConfig::create([ + 'field_name' => 'field_err_single', + 'entity_type' => 'node', + 'type' => 'entity_reference_revisions', + 'settings' => [ + 'target_type' => 'entity_test_composite' + ], + ]); + $field_storage->save(); + $field = FieldConfig::create([ + 'field_storage' => $field_storage, + 'bundle' => 'article', + ]); + $field->save(); + + // Add the field_err_multiple field to the node type. + $field_storage = FieldStorageConfig::create([ + 'field_name' => 'field_err_multiple', + 'entity_type' => 'node', + 'type' => 'entity_reference_revisions', + 'settings' => [ + 'target_type' => 'entity_test_composite' + ], + ]); + $field_storage->save(); + $field = FieldConfig::create([ + 'field_storage' => $field_storage, + 'bundle' => 'article', + ]); + $field->save(); + + $definitions = []; + $instances = []; + foreach ($datas as $data) { + $definitions[$data['definition']['id']] = $data['definition']; + $instances[$data['definition']['id']] = $this->migrationPluginManager->createStubMigration($data['definition']); + } + /*$arguments = [ + $this->container->get('module_handler'), + $this->container->get('cache.discovery'), + $this->container->get('language_manager'), + ]; + $migrationPluginManager = $this->getMock(MigrationPluginManager::class, ['getDefinitions', 'hasDefinition', 'createInstances'], $arguments); + $migrationPluginManager->method('getDefinitions')->willReturn($definitions); + $migrationPluginManager->method('hasDefinition')->willReturn(TRUE); + $migrationPluginManager->method('createInstances')->willReturn($instances); + $this->migrationPluginManager = $migrationPluginManager;*/ + + $reflector = new \ReflectionObject($this->migrationPluginManager); + $property = $reflector->getProperty('definitions'); + $property->setAccessible(TRUE); + $property->setValue($this->migrationPluginManager, $definitions); + $this->container->set('plugin.manager.migration', $this->migrationPluginManager); + + foreach ($datas as $data) { + $migration = $this->migrationPluginManager->createStubMigration($data['definition']); + $migration = $this->migrationPluginManager->createInstance($data['definition']['id']); + $migrationExecutable = (new MigrateExecutable($migration, $this)); + /** @var EntityStorageBase $storage */ + $storage = $this->readAttribute($migration->getDestinationPlugin(), 'storage'); + $migrationExecutable->import(); + foreach ($data['expected'] as $expected) { + $entity = $storage->loadRevision($expected['id']); + $properties = array_filter($expected, function($key) { + return $key != 'id'; + }, ARRAY_FILTER_USE_KEY); + foreach ($properties as $property => $value) { + if (is_array($value)) { + foreach ($value as $delta => $item) { + $this->assertEquals($item, $entity->{$property}[$delta]->target_revision_id); + } + } + else { + $this->assertEquals($expected[$property], $entity->{$property}->value); + } + } + } + } + } + + /** + * Provides multiple migration definitions for "getEntity" test. + */ + public function destinationFieldMappingDataProvider() { + return [ + 'scenario 1' => [ + [ + 'single err' => [ + 'definition' => [ + 'id' => 'single_err', + 'class' => Migration::class, + 'source' => [ + 'plugin' => 'embedded_data', + 'data_rows' => [ + [ + 'id' => 1, + 'title' => 'Main foo', + 'author1' => 'Foo', + 'author2' => 'Baz1', + ], + [ + 'id' => 2, + 'title' => 'Main bar', + 'author1' => 'Bar', + 'author2' => 'Baz2', + ], + ], + 'ids' => [ + 'id' => ['type' => 'integer'], + ], + ], + 'process' => [ + 'name' => 'title', + ], + 'destination' => [ + 'plugin' => 'entity_reference_revisions:entity_test_composite', + ], + ], + 'expected' => [ + ['id' => 1, 'name' => 'Main foo'], + ['id' => 2, 'name' => 'Main bar'], + ], + ], + 'multiple err a' => [ + 'definition' => [ + 'id' => 'multiple_err_a', + 'class' => Migration::class, + 'source' => [ + 'plugin' => 'embedded_data', + 'data_rows' => [ + [ + 'id' => 1, + 'title' => 'Main foo', + 'author1' => 'Foo', + 'author2' => 'Baz1', + ], + [ + 'id' => 2, + 'title' => 'Main bar', + 'author1' => 'Bar', + 'author2' => 'Baz2', + ], + ], + 'ids' => [ + 'id' => ['type' => 'integer'], + ], + ], + 'process' => [ + 'name' => 'author1', + ], + 'destination' => [ + 'plugin' => 'entity_reference_revisions:entity_test_composite', + ], + ], + 'expected' => [ + ['id' => 3, 'name' => 'Foo'], + ['id' => 4, 'name' => 'Bar'], + ], + ], + 'multiple err b' => [ + 'definition' => [ + 'id' => 'multiple_err_b', + 'class' => Migration::class, + 'source' => [ + 'plugin' => 'embedded_data', + 'data_rows' => [ + [ + 'id' => 1, + 'title' => 'Main foo', + 'author1' => 'Foo', + 'author2' => 'Baz1', + ], + [ + 'id' => 2, + 'title' => 'Main bar', + 'author1' => 'Bar', + 'author2' => 'Baz2', + ], + ], + 'ids' => [ + 'id' => ['type' => 'integer'], + ], + ], + 'process' => [ + 'name' => 'author2', + ], + 'destination' => [ + 'plugin' => 'entity_reference_revisions:entity_test_composite', + ], + ], + 'expected' => [ + ['id' => 5, 'name' => 'Baz1'], + ['id' => 6, 'name' => 'Baz2'], + ], + ], + 'destination entity' => [ + 'definition' => [ + 'id' => 'node_migration', + 'class' => Migration::class, + 'source' => [ + 'plugin' => 'embedded_data', + 'data_rows' => [ + [ + 'id' => 1, + 'title' => 'Main foo', + 'author1' => 'Foo', + 'author2' => 'Baz', + ], + [ + 'id' => 2, + 'title' => 'Main bar', + 'author1' => 'Bar', + 'author2' => 'Baz', + ], + ], + 'ids' => [ + 'id' => ['type' => 'integer'], + ], + ], + 'process' => [ + 'title' => 'title', + 'type' => [ + 'plugin' => 'default_value', + 'default_value' => 'article', + ], + 'field_err_single/target_id' => [ + [ + 'plugin' => 'migration', + 'migration' => ['single_err'], + 'no_stub' => TRUE, + 'source' => 'id', + ], + [ + 'plugin' => 'extract', + 'index' => [ + '0', + ], + ], + ], + 'field_err_single/target_revision_id' => [ + [ + 'plugin' => 'migration', + 'migration' => ['single_err'], + 'no_stub' => TRUE, + 'source' => 'id', + ], + [ + 'plugin' => 'extract', + 'index' => [ + 1, + ], + ], + ], + 'field_err_multiple' => [ + [ + 'plugin' => 'concat', + 'delimiter' => ',', + 'source' => ['id','id'], + ], + [ + 'plugin' => 'explode', + 'delimiter' => ',', + ], + [ + 'plugin' => 'migration', + 'migration' => ['multiple_err_a', 'multiple_err_b'], + 'no_stub' => TRUE, + ], + [ + 'plugin' => 'iterator', + 'process' => [ + 'target_id' => '0', + 'target_revision_id' => '1', + ], + ], + ], + ], + 'destination' => [ + 'plugin' => 'entity:node', + ], + ], + 'expected' => [ + [ + 'id' => 1, + 'title' => 'Main foo', + 'field_err_single' => [7], + // @TODO: This won't work unless you are using a custom source + // plugin because migrate process plugin only returns a single + // value. + //'field_err_multiple' => [8, 5], + ], + [ + 'id' => 2, + 'title' => 'Main bar', + 'field_err_single' => [10], + // @TODO: This won't work unless you are using a custom source + // plugin because migrate process plugin only returns a single + // value. + //'field_err_multiple' => [4, 6], + ], + ], + ], + ], + ], + ]; } /**