summaryrefslogtreecommitdiffstatshomepage
path: root/core/modules/migrate
diff options
context:
space:
mode:
Diffstat (limited to 'core/modules/migrate')
-rw-r--r--core/modules/migrate/migrate.api.php4
-rw-r--r--core/modules/migrate/src/MigrateExecutable.php4
-rw-r--r--core/modules/migrate/src/Plugin/Discovery/AnnotatedClassDiscoveryAutomatedProviders.php2
-rw-r--r--core/modules/migrate/src/Plugin/migrate/destination/Config.php2
-rw-r--r--core/modules/migrate/src/Plugin/migrate/source/ConfigEntity.php3
-rw-r--r--core/modules/migrate/src/Plugin/migrate/source/SqlBase.php2
-rw-r--r--core/modules/migrate/src/Row.php26
-rw-r--r--core/modules/migrate/tests/src/Functional/MigrateMessageFormTest.php2
-rw-r--r--core/modules/migrate/tests/src/Functional/MigrateMessageTestBase.php4
-rw-r--r--core/modules/migrate/tests/src/Kernel/RowTest.php152
-rw-r--r--core/modules/migrate/tests/src/Unit/MigrateSourceTest.php2
-rw-r--r--core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityContentBaseTest.php2
-rw-r--r--core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityTestBase.php2
-rw-r--r--core/modules/migrate/tests/src/Unit/RowTest.php37
14 files changed, 229 insertions, 15 deletions
diff --git a/core/modules/migrate/migrate.api.php b/core/modules/migrate/migrate.api.php
index 1e58b0090ff..5d2af7db180 100644
--- a/core/modules/migrate/migrate.api.php
+++ b/core/modules/migrate/migrate.api.php
@@ -156,7 +156,7 @@ function hook_migrate_prepare_row(Row $row, MigrateSourceInterface $source, Migr
if ($migration->id() == 'd6_filter_formats') {
$value = $source->getDatabase()->query('SELECT [value] FROM {variable} WHERE [name] = :name', [':name' => 'my_module_filter_foo_' . $row->getSourceProperty('format')])->fetchField();
if ($value) {
- $row->setSourceProperty('settings:my_module:foo', unserialize($value));
+ $row->setSourceProperty('settings:my_module:foo', unserialize($value, ['allowed_classes' => FALSE]));
}
}
}
@@ -179,7 +179,7 @@ function hook_migrate_prepare_row(Row $row, MigrateSourceInterface $source, Migr
function hook_migrate_MIGRATION_ID_prepare_row(Row $row, MigrateSourceInterface $source, MigrationInterface $migration) {
$value = $source->getDatabase()->query('SELECT [value] FROM {variable} WHERE [name] = :name', [':name' => 'my_module_filter_foo_' . $row->getSourceProperty('format')])->fetchField();
if ($value) {
- $row->setSourceProperty('settings:my_module:foo', unserialize($value));
+ $row->setSourceProperty('settings:my_module:foo', unserialize($value, ['allowed_classes' => FALSE]));
}
}
diff --git a/core/modules/migrate/src/MigrateExecutable.php b/core/modules/migrate/src/MigrateExecutable.php
index a087ae6875e..2cf3a322351 100644
--- a/core/modules/migrate/src/MigrateExecutable.php
+++ b/core/modules/migrate/src/MigrateExecutable.php
@@ -106,7 +106,7 @@ class MigrateExecutable implements MigrateExecutableInterface {
$this->message = $message ?: new MigrateMessage();
$this->getIdMap()->setMessage($this->message);
$this->eventDispatcher = $event_dispatcher;
- // Record the memory limit in bytes
+ // Record the memory limit in bytes.
$limit = trim(ini_get('memory_limit'));
if ($limit == '-1') {
$this->memoryLimit = PHP_INT_MAX;
@@ -557,7 +557,7 @@ class MigrateExecutable implements MigrateExecutableInterface {
$usage = $this->attemptMemoryReclaim();
$pct_memory = $usage / $this->memoryLimit;
// Use a lower threshold - we don't want to be in a situation where we
- // keep coming back here and trimming a tiny amount
+ // keep coming back here and trimming a tiny amount.
if ($pct_memory > (0.90 * $threshold)) {
$this->message->display(
$this->t(
diff --git a/core/modules/migrate/src/Plugin/Discovery/AnnotatedClassDiscoveryAutomatedProviders.php b/core/modules/migrate/src/Plugin/Discovery/AnnotatedClassDiscoveryAutomatedProviders.php
index 9adf60b46ff..30cc28562e8 100644
--- a/core/modules/migrate/src/Plugin/Discovery/AnnotatedClassDiscoveryAutomatedProviders.php
+++ b/core/modules/migrate/src/Plugin/Discovery/AnnotatedClassDiscoveryAutomatedProviders.php
@@ -65,7 +65,7 @@ class AnnotatedClassDiscoveryAutomatedProviders extends AnnotatedClassDiscovery
if (isset($cached['id'])) {
// Explicitly unserialize this to create a new object
// instance.
- $definitions[$cached['id']] = unserialize($cached['content']);
+ $definitions[$cached['id']] = unserialize($cached['content'], ['allowed_classes' => FALSE]);
}
continue;
}
diff --git a/core/modules/migrate/src/Plugin/migrate/destination/Config.php b/core/modules/migrate/src/Plugin/migrate/destination/Config.php
index c77de935a52..2e6c26a1684 100644
--- a/core/modules/migrate/src/Plugin/migrate/destination/Config.php
+++ b/core/modules/migrate/src/Plugin/migrate/destination/Config.php
@@ -234,7 +234,7 @@ class Config extends DestinationBase implements ContainerFactoryPluginInterface,
return 'config_translation';
}
// Get the module handling this configuration object from the config_name,
- // which is of the form <module_name>.<configuration object name>
+ // which is of the form "<module_name>.<configuration object name>".
return !empty($this->configuration['config_name']) ? explode('.', $this->configuration['config_name'], 2)[0] : NULL;
}
diff --git a/core/modules/migrate/src/Plugin/migrate/source/ConfigEntity.php b/core/modules/migrate/src/Plugin/migrate/source/ConfigEntity.php
index dc70496282f..a5351c74862 100644
--- a/core/modules/migrate/src/Plugin/migrate/source/ConfigEntity.php
+++ b/core/modules/migrate/src/Plugin/migrate/source/ConfigEntity.php
@@ -71,7 +71,8 @@ class ConfigEntity extends SqlBase {
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
- $row->setSourceProperty('data', unserialize($row->getSourceProperty('data')));
+ // @see \Drupal\Core\Config\DatabaseStorage::decode()
+ $row->setSourceProperty('data', unserialize($row->getSourceProperty('data'), ['allowed_classes' => FALSE]));
return parent::prepareRow($row);
}
diff --git a/core/modules/migrate/src/Plugin/migrate/source/SqlBase.php b/core/modules/migrate/src/Plugin/migrate/source/SqlBase.php
index 40dea1c7a2b..0aefdd99de2 100644
--- a/core/modules/migrate/src/Plugin/migrate/source/SqlBase.php
+++ b/core/modules/migrate/src/Plugin/migrate/source/SqlBase.php
@@ -424,7 +424,7 @@ abstract class SqlBase extends SourcePluginBase implements ContainerFactoryPlugi
}
// If we are tracking changes, we also need to retrieve all rows to compare
- // hashes
+ // hashes.
if ($this->trackChanges) {
return FALSE;
}
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/Functional/MigrateMessageFormTest.php b/core/modules/migrate/tests/src/Functional/MigrateMessageFormTest.php
index cfbcdf5b4df..22f6c4fbc46 100644
--- a/core/modules/migrate/tests/src/Functional/MigrateMessageFormTest.php
+++ b/core/modules/migrate/tests/src/Functional/MigrateMessageFormTest.php
@@ -45,7 +45,7 @@ class MigrateMessageFormTest extends MigrateMessageTestBase {
$this->assertEquals($expected_count, $count[$level], sprintf('Count for level %s failed', $level));
}
- // Reset the filter
+ // Reset the filter.
$this->submitForm([], 'Reset');
$messages = $this->getMessages();
$this->assertCount(4, $messages);
diff --git a/core/modules/migrate/tests/src/Functional/MigrateMessageTestBase.php b/core/modules/migrate/tests/src/Functional/MigrateMessageTestBase.php
index 6885ba378e9..84dddc3c182 100644
--- a/core/modules/migrate/tests/src/Functional/MigrateMessageTestBase.php
+++ b/core/modules/migrate/tests/src/Functional/MigrateMessageTestBase.php
@@ -12,10 +12,8 @@ use Drupal\migrate\Plugin\MigrationInterface;
/**
* Provides base class for testing migrate messages.
- *
- * @group migrate
*/
-class MigrateMessageTestBase extends BrowserTestBase {
+abstract class MigrateMessageTestBase extends BrowserTestBase {
/**
* {@inheritdoc}
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/MigrateSourceTest.php b/core/modules/migrate/tests/src/Unit/MigrateSourceTest.php
index e344e3e23e8..77e4cf64e64 100644
--- a/core/modules/migrate/tests/src/Unit/MigrateSourceTest.php
+++ b/core/modules/migrate/tests/src/Unit/MigrateSourceTest.php
@@ -426,7 +426,7 @@ class MigrateSourceTest extends MigrateTestCase {
$migration = $this->getMigration();
$source = new StubSourceGeneratorPlugin([], '', [], $migration);
- // Test the default value of the skipCount Value;
+ // Test the default value of the skipCount Value.
$this->assertTrue($source->getSkipCount());
$this->assertTrue($source->getCacheCounts());
$this->assertTrue($source->getTrackChanges());
diff --git a/core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityContentBaseTest.php b/core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityContentBaseTest.php
index 1cabbebdde6..aefd45d0438 100644
--- a/core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityContentBaseTest.php
+++ b/core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityContentBaseTest.php
@@ -47,7 +47,7 @@ class EntityContentBaseTest extends EntityTestBase {
// Syncing should be set once.
$entity->setSyncing(Argument::exact(TRUE))
->shouldBeCalledTimes(1);
- // Set an id for the entity
+ // Set an id for the entity.
$entity->id()
->willReturn(5);
$destination->setEntity($entity->reveal());
diff --git a/core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityTestBase.php b/core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityTestBase.php
index ba9ab78cff6..ed223601abb 100644
--- a/core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityTestBase.php
+++ b/core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityTestBase.php
@@ -14,7 +14,7 @@ use Drupal\Tests\UnitTestCase;
/**
* Base test class for entity migration destination functionality.
*/
-class EntityTestBase extends UnitTestCase {
+abstract class EntityTestBase extends UnitTestCase {
/**
* The migration entity.
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 {