diff --git a/tests/src/Kernel/Plugin/migrate/process/EntityLookupTest.php b/tests/src/Kernel/Plugin/migrate/process/EntityLookupTest.php new file mode 100644 index 0000000..4713a3b --- /dev/null +++ b/tests/src/Kernel/Plugin/migrate/process/EntityLookupTest.php @@ -0,0 +1,493 @@ + $this->bundle, + 'name' => 'Page', + ]; + $node_type = NodeType::create($values); + $node_type->save(); + + $this->installEntitySchema('node'); + $this->installEntitySchema('taxonomy_term'); + $this->installEntitySchema('taxonomy_vocabulary'); + $this->installEntitySchema('user'); + $this->installSchema('system', ['sequences']); + $this->installSchema('user', 'users_data'); + $this->installConfig($this->modules); + + // Create a vocabulary. + $vocabulary = Vocabulary::create([ + 'name' => $this->vocabulary, + 'description' => $this->vocabulary, + 'vid' => $this->vocabulary, + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + ]); + $vocabulary->save(); + + // Create a field. + $this->createEntityReferenceField( + 'node', + $this->bundle, + $this->fieldName, + 'Term reference', + 'taxonomy_term', + 'default', + ['target_bundles' => [$this->vocabulary]], + FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED + ); + + $this->migrationPluginManager = \Drupal::service('plugin.manager.migration'); + } + + /** + * Tests generating an entity. + * + * @dataProvider transformDataProvider + * + * @covers ::transform + */ + public function testTransform(array $definition, array $expected, array $preSeed = []) { + // Pre seed some test data. + foreach ($preSeed as $storageName => $values) { + // If the first element of $values is an array, create multiple entities. + // Otherwise, create just one entity. + if (isset($values[0])) { + foreach ($values as $itemValues) { + $this->createTestData($storageName, $itemValues); + } + } + else { + $this->createTestData($storageName, $values); + } + } + + /** @var Drupal\migrate\Plugin\Migration $migration */ + $migration = $this->migrationPluginManager->createStubMigration($definition); + /** @var EntityStorageBase $storage */ + $storage = $this->readAttribute($migration->getDestinationPlugin(), 'storage'); + $migrationExecutable = (new MigrateExecutable($migration, $this)); + $migrationExecutable->import(); + + foreach ($expected as $row) { + $entity = $storage->load($row['id']); + $properties = array_diff_key($row, array_flip(['id'])); + foreach ($properties as $property => $value) { + if (is_array($value)) { + if (empty($value)) { + $this->assertEmpty($entity->{$property}->getValue(), "Expected value is 'unset' but field $property is set."); + } + else { + // Check if we're testing multiple values in one field. If so, loop + // through them one-by-one and check that they're present in the + // $entity. + if (isset($value[0])) { + foreach ($value as $valueID => $valueToCheck) { + foreach ($valueToCheck as $key => $expectedValue) { + if (empty($expectedValue)) { + $this->assertEmpty($entity->{$property}[$valueID]->getValue(), "Expected value is empty but field $property, index $valueID is not empty."); + } + elseif ($entity->{$property}[$valueID]->getValue()) { + $this->assertEquals($expectedValue, $entity->{$property}[$valueID]->entity->$key->value); + } + else { + $this->fail("Expected value: $expectedValue does not exist in $property, index $valueID."); + } + } + } + } + // If we get to this point, we're only checking a + // single field value. + else { + foreach ($value as $key => $expectedValue) { + if (empty($expectedValue)) { + $this->assertEmpty($entity->{$property}->getValue(), "Expected value is empty but field $property is not empty."); + } + elseif ($entity->{$property}->getValue()) { + $this->assertEquals($expectedValue, $entity->{$property}[0]->entity->$key->value); + } + else { + $this->fail("Expected value: $expectedValue does not exist in $property."); + } + } + } + } + } + else { + $this->assertNotEmpty($entity, 'Entity with label ' . $row[$property] . ' is empty'); + $this->assertEquals($row[$property], $entity->label()); + } + } + } + } + + /** + * Provides multiple migration definitions for "transform" test. + */ + public function transformDataProvider() { + return [ + 'lookup single existing term returns correct term' => [ + 'definition' => [ + 'source' => [ + 'plugin' => 'embedded_data', + 'data_rows' => [ + [ + 'id' => 1, + 'title' => 'content item 1', + 'term' => 'Grapes', + ], + ], + 'ids' => [ + 'id' => ['type' => 'integer'], + ], + ], + 'process' => [ + 'id' => 'id', + 'type' => [ + 'plugin' => 'default_value', + 'default_value' => $this->bundle, + ], + 'title' => 'title', + $this->fieldName => [ + 'plugin' => 'entity_lookup', + 'source' => 'term', + ], + ], + 'destination' => [ + 'plugin' => 'entity:node', + ], + ], + 'expected' => [ + 'row 1' => [ + 'id' => 1, + 'title' => 'content item 1', + $this->fieldName => [ + 'tid' => 1, + 'name' => 'Grapes', + ], + ], + ], + 'pre seed' => [ + 'taxonomy_term' => [ + 'name' => 'Grapes', + 'vid' => $this->vocabulary, + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + ], + ], + ], + 'lookup single missing term returns null value' => [ + 'definition' => [ + 'source' => [ + 'plugin' => 'embedded_data', + 'data_rows' => [ + [ + 'id' => 1, + 'title' => 'content item 1', + 'term' => 'Apple', + ], + ], + 'ids' => [ + 'id' => ['type' => 'integer'], + ], + ], + 'process' => [ + 'id' => 'id', + 'type' => [ + 'plugin' => 'default_value', + 'default_value' => $this->bundle, + ], + 'title' => 'title', + $this->fieldName => [ + 'plugin' => 'entity_lookup', + 'source' => 'term', + ], + ], + 'destination' => [ + 'plugin' => 'entity:node', + ], + ], + 'expected' => [ + 'row 1' => [ + 'id' => 1, + 'title' => 'content item 1', + $this->fieldName => [], + ], + ], + 'pre seed' => [ + 'taxonomy_term' => [ + 'name' => 'Grapes', + 'vid' => $this->vocabulary, + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + ], + ], + ], + 'lookup multiple existing terms returns correct terms' => [ + 'definition' => [ + 'source' => [ + 'plugin' => 'embedded_data', + 'data_rows' => [ + [ + 'id' => 1, + 'title' => 'content item 1', + 'term' => [ + 'Grapes', + 'Apples', + ], + ], + ], + 'ids' => [ + 'id' => ['type' => 'integer'], + ], + ], + 'process' => [ + 'id' => 'id', + 'title' => 'title', + 'type' => [ + 'plugin' => 'default_value', + 'default_value' => $this->bundle, + ], + $this->fieldName => [ + 'plugin' => 'entity_lookup', + 'source' => 'term', + ], + ], + 'destination' => [ + 'plugin' => 'entity:node', + ], + ], + 'expected' => [ + 'row 1' => [ + 'id' => 1, + 'title' => 'content item 1', + $this->fieldName => [ + [ + 'tid' => 1, + 'name' => 'Grapes', + ], + [ + 'tid' => 2, + 'name' => 'Apples', + ], + ], + ], + ], + 'pre seed' => [ + 'taxonomy_term' => [ + [ + 'name' => 'Grapes', + 'vid' => $this->vocabulary, + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + ], + [ + 'name' => 'Apples', + 'vid' => $this->vocabulary, + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + ], + ], + ], + ], + 'lookup multiple mixed terms returns correct terms' => [ + 'definition' => [ + 'source' => [ + 'plugin' => 'embedded_data', + 'data_rows' => [ + [ + 'id' => 1, + 'title' => 'content item 1', + 'term' => [ + 'Grapes', + 'Pears', + ], + ], + ], + 'ids' => [ + 'id' => ['type' => 'integer'], + ], + ], + 'process' => [ + 'id' => 'id', + 'title' => 'title', + 'type' => [ + 'plugin' => 'default_value', + 'default_value' => $this->bundle, + ], + $this->fieldName => [ + 'plugin' => 'entity_lookup', + 'source' => 'term', + ], + ], + 'destination' => [ + 'plugin' => 'entity:node', + ], + ], + 'expected' => [ + 'row 1' => [ + 'id' => '1', + 'title' => 'content item 1', + $this->fieldName => [ + [ + 'tid' => 1, + 'name' => 'Grapes', + ], + ], + ], + ], + 'pre seed' => [ + 'taxonomy_term' => [ + [ + 'name' => 'Grapes', + 'vid' => $this->vocabulary, + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + ], + [ + 'name' => 'Apples', + 'vid' => $this->vocabulary, + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + ], + ], + ], + ], + 'lookup with empty term value returns no terms' => [ + 'definition' => [ + 'source' => [ + 'plugin' => 'embedded_data', + 'data_rows' => [ + [ + 'id' => 1, + 'title' => 'content item 1', + 'term' => [], + ], + ], + 'ids' => [ + 'id' => ['type' => 'integer'], + ], + ], + 'process' => [ + 'id' => 'id', + 'title' => 'title', + 'type' => [ + 'plugin' => 'default_value', + 'default_value' => $this->bundle, + ], + $this->fieldName => [ + 'plugin' => 'entity_lookup', + 'source' => 'term', + ], + ], + 'destination' => [ + 'plugin' => 'entity:node', + ], + ], + 'expected' => [ + 'row 1' => [ + 'id' => 1, + 'title' => 'content item 1', + $this->fieldName => [], + ], + ], + 'pre seed' => [ + 'taxonomy_term' => [ + 'name' => 'Grapes', + 'vid' => $this->vocabulary, + 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, + ], + ], + ], + ]; + } + + /** + * {@inheritdoc} + */ + public function display($message, $type = 'status') { + $this->assertTrue($type == 'status', $message); + } + + /** + * Create pre-seed test data. + * + * @param string $storageName + * The storage manager to create. + * @param array $values + * The values to use when creating the entity. + */ + private function createTestData($storageName, array $values) { + /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */ + $storage = $this->container + ->get('entity_type.manager') + ->getStorage($storageName); + $entity = $storage->create($values); + $entity->save(); + } + +}