summaryrefslogtreecommitdiffstatshomepage
path: root/core/modules/migrate
diff options
context:
space:
mode:
Diffstat (limited to 'core/modules/migrate')
-rw-r--r--core/modules/migrate/src/Row.php26
-rw-r--r--core/modules/migrate/tests/src/Kernel/RowTest.php152
-rw-r--r--core/modules/migrate/tests/src/Unit/RowTest.php37
3 files changed, 215 insertions, 0 deletions
diff --git a/core/modules/migrate/src/Row.php b/core/modules/migrate/src/Row.php
index 3d961902bcd..2b5e8b2fb4e 100644
--- a/core/modules/migrate/src/Row.php
+++ b/core/modules/migrate/src/Row.php
@@ -267,6 +267,32 @@ class Row {
}
/**
+ * Tests if a property is an empty destination.
+ *
+ * @param string $property
+ * The name of the property.
+ *
+ * @return bool
+ * TRUE if the property is an empty destination.
+ */
+ public function hasEmptyDestinationProperty(string $property): bool {
+ return in_array($property, $this->emptyDestinationProperties);
+ }
+
+ /**
+ * Removes an empty destination property.
+ *
+ * @param string $property
+ * The name of the empty destination property.
+ */
+ public function removeEmptyDestinationProperty(string $property): void {
+ $this->emptyDestinationProperties = array_diff(
+ $this->emptyDestinationProperties,
+ [$property],
+ );
+ }
+
+ /**
* Returns the whole destination array.
*
* @return array
diff --git a/core/modules/migrate/tests/src/Kernel/RowTest.php b/core/modules/migrate/tests/src/Kernel/RowTest.php
new file mode 100644
index 00000000000..1b4adf181c8
--- /dev/null
+++ b/core/modules/migrate/tests/src/Kernel/RowTest.php
@@ -0,0 +1,152 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\Tests\migrate\Kernel;
+
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\migrate\Event\MigratePreRowSaveEvent;
+use Drupal\migrate\Event\MigrateEvents;
+use Drupal\migrate\MigrateExecutable;
+use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+
+/**
+ * Tests the Row class.
+ *
+ * @group migrate
+ */
+class RowTest extends KernelTestBase {
+
+ /**
+ * The event dispatcher.
+ */
+ protected EventDispatcherInterface $eventDispatcher;
+
+ /**
+ * The entity type manager.
+ */
+ protected EntityTypeManagerInterface $entityTypeManager;
+
+ /**
+ * The migration manager.
+ */
+ protected MigrationPluginManagerInterface $migrationManager;
+
+ /**
+ * {@inheritdoc}
+ */
+ protected static $modules = [
+ 'entity_test',
+ 'field',
+ 'migrate',
+ 'user',
+ ];
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp(): void {
+ parent::setUp();
+ $this->installEntitySchema('entity_test');
+
+ $this->eventDispatcher = \Drupal::service('event_dispatcher');
+ $this->entityTypeManager = \Drupal::service('entity_type.manager');
+ $this->migrationManager = \Drupal::service('plugin.manager.migration');
+
+ // Create two fields that will be set during migration.
+ $fields = ['field1', 'field2'];
+ foreach ($fields as $field) {
+ $this->entityTypeManager->getStorage('field_storage_config')->create([
+ 'entity_type' => 'entity_test',
+ 'field_name' => $field,
+ 'type' => 'string',
+ ])->save();
+ $this->entityTypeManager->getStorage('field_config')->create([
+ 'entity_type' => 'entity_test',
+ 'field_name' => $field,
+ 'bundle' => 'entity_test',
+ ])->save();
+ }
+ }
+
+ /**
+ * Tests the destination properties of the Row class.
+ */
+ public function testRowDestinations(): void {
+ $storage = $this->entityTypeManager->getStorage('entity_test');
+
+ // Execute a migration that creates an entity with two fields.
+ $data_rows = [
+ ['id' => 1, 'field1' => 'f1value', 'field2' => 'f2value'],
+ ];
+ $ids = ['id' => ['type' => 'integer']];
+ $definition = [
+ 'source' => [
+ 'plugin' => 'embedded_data',
+ 'data_rows' => $data_rows,
+ 'ids' => $ids,
+ ],
+ 'process' => [
+ 'id' => 'id',
+ 'field1' => 'field1',
+ 'field2' => 'field2',
+ ],
+ 'destination' => ['plugin' => 'entity:entity_test'],
+ ];
+ $this->executeMigrationImport($definition);
+ $entity = $storage->load(1);
+ $this->assertEquals('f1value', $entity->get('field1')->getValue()[0]['value']);
+ $this->assertEquals('f2value', $entity->get('field2')->getValue()[0]['value']);
+
+ // Execute a second migration that attempts to remove both field values.
+ // The event listener prevents the removal of the second field.
+ $data_rows = [
+ ['id' => 1, 'field1' => NULL, 'field2' => NULL],
+ ];
+ $definition['source']['data_rows'] = $data_rows;
+ $this->eventDispatcher->addListener(MigrateEvents::PRE_ROW_SAVE, [$this, 'preventFieldRemoval']);
+ $this->executeMigrationImport($definition);
+
+ // The first field is now empty but the second field is still set.
+ $entity = $storage->load(1);
+ $this->assertTrue($entity->get('field1')->isEmpty());
+ $this->assertEquals('f2value', $entity->get('field2')->getValue()[0]['value']);
+ }
+
+ /**
+ * The pre-row-save event handler for the second migration.
+ *
+ * Checks row destinations and prevents the removal of the second field.
+ *
+ * @param \Drupal\migrate\Event\MigratePreRowSaveEvent $event
+ * The migration event.
+ * @param string $name
+ * The event name.
+ */
+ public function preventFieldRemoval(MigratePreRowSaveEvent $event, string $name): void {
+ $row = $event->getRow();
+
+ // Both fields are empty and their existing values will be removed.
+ $this->assertFalse($row->hasDestinationProperty('field1'));
+ $this->assertFalse($row->hasDestinationProperty('field2'));
+ $this->assertTrue($row->hasEmptyDestinationProperty('field1'));
+ $this->assertTrue($row->hasEmptyDestinationProperty('field2'));
+
+ // Prevent removal of field 2.
+ $row->removeEmptyDestinationProperty('field2');
+ }
+
+ /**
+ * Executes a migration import for the given migration definition.
+ *
+ * @param array $definition
+ * The migration definition.
+ */
+ protected function executeMigrationImport(array $definition): void {
+ $migration = $this->migrationManager->createStubMigration($definition);
+ (new MigrateExecutable($migration))->import();
+ }
+
+}
diff --git a/core/modules/migrate/tests/src/Unit/RowTest.php b/core/modules/migrate/tests/src/Unit/RowTest.php
index 69fce6f7860..7db1a51db43 100644
--- a/core/modules/migrate/tests/src/Unit/RowTest.php
+++ b/core/modules/migrate/tests/src/Unit/RowTest.php
@@ -292,6 +292,43 @@ class RowTest extends UnitTestCase {
}
/**
+ * Tests checking for and removing destination properties that may be empty.
+ *
+ * @covers ::hasEmptyDestinationProperty
+ * @covers ::removeEmptyDestinationProperty
+ */
+ public function testDestinationOrEmptyProperty(): void {
+ $row = new Row($this->testValues, $this->testSourceIds);
+
+ // Set a destination.
+ $row->setDestinationProperty('nid', 2);
+ $this->assertTrue($row->hasDestinationProperty('nid'));
+ $this->assertFalse($row->hasEmptyDestinationProperty('nid'));
+
+ // Set an empty destination.
+ $row->setEmptyDestinationProperty('a_property_with_no_value');
+ $this->assertTrue($row->hasEmptyDestinationProperty('a_property_with_no_value'));
+ $this->assertFalse($row->hasDestinationProperty('a_property_with_no_value'));
+
+ // Removing an empty destination that is not actually empty has no effect.
+ $row->removeEmptyDestinationProperty('nid');
+ $this->assertTrue($row->hasDestinationProperty('nid'));
+ $this->assertFalse($row->hasEmptyDestinationProperty('nid'));
+
+ // Removing a destination that is actually empty has no effect.
+ $row->removeDestinationProperty('a_property_with_no_value');
+ $this->assertTrue($row->hasEmptyDestinationProperty('a_property_with_no_value'));
+
+ // Remove the empty destination.
+ $row->removeEmptyDestinationProperty('a_property_with_no_value');
+ $this->assertFalse($row->hasEmptyDestinationProperty('a_property_with_no_value'));
+
+ // Removing a destination that does not exist does not throw an error.
+ $this->assertFalse($row->hasEmptyDestinationProperty('not_a_property'));
+ $row->removeEmptyDestinationProperty('not_a_property');
+ }
+
+ /**
* Tests setting/getting multiple destination IDs.
*/
public function testMultipleDestination(): void {