/** * @covers ::processCckFieldValues */ public function testProcessBooleanTextExplicitValues() { $info = array('widget_type' => 'optionwidgets_onoff', 'global_settings' => array('allowed_values' => "foo|Foo\nbaz|Baz")); $this->plugin->processCckFieldValues($this->migration, 'field', $info); $expected = ['value' => ['plugin' => 'static_map', 'source' => 'value', 'default_value' => 0, 'map' => ['baz' => 1]]]; $this->assertSame($expected, $this->migration->getProcess()['process']); }
/** * Test row skipping when we can't get an entity to save. * * @covers ::import * @expectedException \Drupal\migrate\MigrateException * @expectedExceptionMessage Unable to get entity */ public function testImportEntityLoadFailure() { $bundles = []; $destination = new EntityTestDestination([], '', [], $this->migration->reveal(), $this->storage->reveal(), $bundles, $this->entityManager->reveal(), $this->prophesize(FieldTypePluginManagerInterface::class)->reveal()); $destination->setEntity(FALSE); $destination->import(new Row([], [])); }
/** * {@inheritdoc} */ public function processFieldFormatter(MigrationInterface $migration) { $process = []; foreach ($this->getFieldFormatterMap() as $source_format => $destination_format) { $process[0]['map'][$this->pluginId][$source_format] = $destination_format; } $migration->mergeProcessOfProperty('options/type', $process); }
/** * {@inheritdoc} */ protected function prepareMigration(MigrationInterface $migration) { // File migrations need a source_base_path. // @see MigrateUpgradeRunBatch::run $destination = $migration->getDestinationConfiguration(); if ($destination['plugin'] === 'entity:file') { // Make sure we have a single trailing slash. $source = $migration->getSourceConfiguration(); $source['site_path'] = 'core/modules/simpletest'; $source['constants']['source_base_path'] = \Drupal::root() . '/'; $migration->set('source', $source); } }
/** * {@inheritdoc} * * The migration iterates over rows returned by the source plugin. This * method determines the next row which will be processed and imported into * the system. * * The method tracks the source and destination IDs using the ID map plugin. * * This also takes care about highwater support. Highwater allows to reimport * rows from a previous migration run, which got changed in the meantime. * This is done by specifying a highwater field, which is compared with the * last time, the migration got executed (originalHighWater). */ public function next() { $this->currentSourceIds = NULL; $this->currentRow = NULL; // In order to find the next row we want to process, we ask the source // plugin for the next possible row. while (!isset($this->currentRow) && $this->getIterator()->valid()) { $row_data = $this->getIterator()->current() + $this->configuration; $this->getIterator()->next(); $row = new Row($row_data, $this->migration->getSourcePlugin()->getIds(), $this->migration->get('destinationIds')); // Populate the source key for this row. $this->currentSourceIds = $row->getSourceIdValues(); // Pick up the existing map row, if any, unless getNextRow() did it. if (!$this->mapRowAdded && ($id_map = $this->idMap->getRowBySource($this->currentSourceIds))) { $row->setIdMap($id_map); } // Clear any previous messages for this row before potentially adding // new ones. if (!empty($this->currentSourceIds)) { $this->idMap->delete($this->currentSourceIds, TRUE); } // Preparing the row gives source plugins the chance to skip. if ($this->prepareRow($row) === FALSE) { continue; } // Check whether the row needs processing. // 1. This row has not been imported yet. // 2. Explicitly set to update. // 3. The row is newer than the current highwater mark. // 4. If no such property exists then try by checking the hash of the row. if (!$row->getIdMap() || $row->needsUpdate() || $this->aboveHighwater($row) || $this->rowChanged($row)) { $this->currentRow = $row->freezeSource(); } } }
/** * Tests the processRow method with an empty pipeline. */ public function testProcessRowEmptyPipeline() { $this->migration->expects($this->once())->method('getProcessPlugins')->with(NULL)->will($this->returnValue(array('test' => array()))); $row = new Row(array(), array()); $this->executable->processRow($row); $this->assertSame($row->getDestination(), array()); }
/** * {@inheritdoc} */ public function saveIdMapping(Row $row, array $destination_id_values, $source_row_status = MigrateIdMapInterface::STATUS_IMPORTED, $rollback_action = MigrateIdMapInterface::ROLLBACK_DELETE) { // Construct the source key. $source_id_values = $row->getSourceIdValues(); // Construct the source key and initialize to empty variable keys. $fields = []; foreach ($this->sourceIdFields() as $field_name => $key_name) { // A NULL key value is usually an indication of a problem. if (!isset($source_id_values[$field_name])) { $this->message->display($this->t('Did not save to map table due to NULL value for key field @field', array('@field' => $field_name)), 'error'); return; } $fields[$key_name] = $source_id_values[$field_name]; } if (!$fields) { return; } $fields += array('source_row_status' => (int) $source_row_status, 'rollback_action' => (int) $rollback_action, 'hash' => $row->getHash()); $count = 0; foreach ($destination_id_values as $dest_id) { $fields['destid' . ++$count] = $dest_id; } if ($count && $count != count($this->destinationIdFields())) { $this->message->display(t('Could not save to map table due to missing destination id values'), 'error'); return; } if ($this->migration->getTrackLastImported()) { $fields['last_imported'] = time(); } $keys = [static::SOURCE_IDS_HASH => $this->getSourceIDsHash($source_id_values)]; // Notify anyone listening of the map row we're about to save. $this->eventDispatcher->dispatch(MigrateEvents::MAP_SAVE, new MigrateMapSaveEvent($this, $fields)); $this->getDatabase()->merge($this->mapTableName())->key($keys)->fields($fields)->execute(); }
/** * {@inheritdoc} */ public function processCckFieldValues(MigrationInterface $migration, $field_name, $field_info) { if ($field_info['widget_type'] == 'optionwidgets_onoff') { $process = ['value' => ['plugin' => 'static_map', 'source' => 'value', 'default_value' => 0]]; $checked_value = explode("\n", $field_info['global_settings']['allowed_values'])[1]; if (strpos($checked_value, '|') !== FALSE) { $checked_value = substr($checked_value, 0, strpos($checked_value, '|')); } $process['value']['map'][$checked_value] = 1; } else { // See \Drupal\migrate_drupal\Plugin\migrate\source\d6\User::baseFields(), // signature_format for an example of the YAML that represents this // process array. $process = ['value' => 'value', 'format' => [['plugin' => 'static_map', 'bypass' => TRUE, 'source' => 'format', 'map' => [0 => NULL]], ['plugin' => 'skip_on_empty', 'method' => 'process'], ['plugin' => 'migration', 'migration' => ['d6_filter_format', 'd7_filter_format'], 'source' => 'format']]]; } $process = array('plugin' => 'iterator', 'source' => $field_name, 'process' => $process); $migration->setProcessOfProperty($field_name, $process); }
/** * Test that translation destination fails for untranslatable entities. * * @expectedException \Drupal\migrate\MigrateException * @expectedExceptionMessage This entity type does not support translation */ public function testUntranslatable() { // An entity type without a language. $entity_type = $this->prophesize(ContentEntityType::class); $entity_type->getKey('langcode')->willReturn(''); $entity_type->getKey('id')->willReturn('id'); $this->storage->getEntityType()->willReturn($entity_type->reveal()); $destination = new EntityTestDestination(['translations' => TRUE], '', [], $this->migration->reveal(), $this->storage->reveal(), [], $this->entityManager->reveal(), $this->prophesize(FieldTypePluginManagerInterface::class)->reveal()); $destination->getIds(); }
/** * Test that an outdated highwater mark does not cause a row to be imported. */ public function testOutdatedHighwater() { $source = $this->getSource([], [], MigrateIdMapInterface::STATUS_IMPORTED); // Set the originalHighwater to something higher than our timestamp. $this->migration->expects($this->any())->method('getHighwater')->willReturn($this->row['timestamp'] + 1); // The current highwater mark is now higher than the row timestamp so no row // is expected. $source->rewind(); $this->assertNull($source->current(), 'Original highwater mark is higher than incoming row timestamp.'); }
/** * {@inheritdoc} */ public function getPluginIdFromFieldType($field_type, array $configuration = [], MigrationInterface $migration = NULL) { $core = static::DEFAULT_CORE_VERSION; if (!empty($configuration['core'])) { $core = $configuration['core']; } elseif (!empty($migration->getPluginDefinition()['migration_tags'])) { foreach ($migration->getPluginDefinition()['migration_tags'] as $tag) { if ($tag == 'Drupal 7') { $core = 7; } } } foreach ($this->getDefinitions() as $plugin_id => $definition) { if (in_array($core, $definition['core'])) { if (array_key_exists($field_type, $definition['type_map']) || $field_type === $plugin_id) { return $plugin_id; } } } throw new PluginNotFoundException($field_type); }
/** * Instantiates the source plugin under test. * * @param array $configuration * The source plugin configuration. * * @return \Drupal\migrate\Plugin\MigrateSourceInterface|object * The fully configured source plugin. */ protected function getPlugin(array $configuration) { // Only create the plugin once per test. if ($this->plugin) { return $this->plugin; } $class = ltrim($this->getPluginClass(), '\\'); /** @var \Drupal\migrate\Plugin\MigratePluginManager $plugin_manager */ $plugin_manager = $this->container->get('plugin.manager.migrate.source'); foreach ($plugin_manager->getDefinitions() as $id => $definition) { if (ltrim($definition['class'], '\\') == $class) { $this->plugin = $plugin_manager->createInstance($id, $configuration, $this->migration->reveal()); $this->migration->getSourcePlugin()->willReturn($this->plugin); return $this->plugin; } } $this->fail('No plugin found for class ' . $class); }
/** * Gets the source plugin to test. * * @param array $configuration * (optional) The source configuration. Defaults to an empty array. * @param array $migrate_config * (optional) The migration configuration to be used in * parent::getMigration(). Defaults to an empty array. * @param int $status * (optional) The default status for the new rows to be imported. Defaults * to MigrateIdMapInterface::STATUS_NEEDS_UPDATE. * * @return \Drupal\migrate\Plugin\MigrateSourceInterface * A mocked source plugin. */ protected function getSource($configuration = [], $migrate_config = [], $status = MigrateIdMapInterface::STATUS_NEEDS_UPDATE, $high_water_value = NULL) { $container = new ContainerBuilder(); \Drupal::setContainer($container); $key_value = $this->getMock(KeyValueStoreInterface::class); $key_value_factory = $this->getMock(KeyValueFactoryInterface::class); $key_value_factory->method('get')->with('migrate:high_water')->willReturn($key_value); $container->set('keyvalue', $key_value_factory); $container->set('cache.migrate', $this->getMock(CacheBackendInterface::class)); $this->migrationConfiguration = $this->defaultMigrationConfiguration + $migrate_config; $this->migration = parent::getMigration(); $this->executable = $this->getMigrateExecutable($this->migration); // Update the idMap for Source so the default is that the row has already // been imported. This allows us to use the highwater mark to decide on the // outcome of whether we choose to import the row. $id_map_array = ['original_hash' => '', 'hash' => '', 'source_row_status' => $status]; $this->idMap->expects($this->any())->method('getRowBySource')->willReturn($id_map_array); $constructor_args = [$configuration, 'd6_action', [], $this->migration]; $methods = ['getModuleHandler', 'fields', 'getIds', '__toString', 'prepareRow', 'initializeIterator']; $source_plugin = $this->getMock(SourcePluginBase::class, $methods, $constructor_args); $source_plugin->method('fields')->willReturn([]); $source_plugin->method('getIds')->willReturn([]); $source_plugin->method('__toString')->willReturn(''); $source_plugin->method('prepareRow')->willReturn(empty($migrate_config['prepare_row_false'])); $rows = [$this->row]; if (isset($configuration['high_water_property']) && isset($high_water_value)) { $property = $configuration['high_water_property']['name']; $rows = array_filter($rows, function (array $row) use($property, $high_water_value) { return $row[$property] >= $high_water_value; }); } $iterator = new \ArrayIterator($rows); $source_plugin->method('initializeIterator')->willReturn($iterator); $module_handler = $this->getMock(ModuleHandlerInterface::class); $source_plugin->method('getModuleHandler')->willReturn($module_handler); $this->migration->method('getSourcePlugin')->willReturn($source_plugin); return $source_plugin; }
/** * Save the new high water mark. * * @param int $high_water * The high water timestamp. */ protected function saveHighWater($high_water) { $this->getHighWaterStorage()->set($this->migration->id(), $high_water); }
/** * {@inheritdoc} */ public function processCckFieldValues(MigrationInterface $migration, $field_name, $data) { $process = array('plugin' => 'iterator', 'source' => $field_name, 'process' => array('target_id' => 'tid')); $migration->setProcessOfProperty($field_name, $process); }
/** * {@inheritdoc} */ public function processCckFieldValues(MigrationInterface $migration, $field_name, $data) { $process = ['plugin' => 'iterator', 'source' => $field_name, 'process' => ['target_id' => 'fid', 'display' => 'display', 'description' => 'description']]; $migration->mergeProcessOfProperty($field_name, $process); }
/** * {@inheritdoc} */ public function saveMessage($message, $level = MigrationInterface::MESSAGE_ERROR) { $this->migration->getIdMap()->saveMessage($this->sourceIdValues, $message, $level); }
/** * {@inheritdoc} */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) { $migration_configuration['migration'][] = $migration->id(); return new static($configuration, $plugin_id, $plugin_definition, $container->get('plugin.manager.migrate.process')->createInstance('migration', $migration_configuration, $migration), $container->get('plugin.manager.menu.link'), $container->get('entity.manager')->getStorage('menu_link_content')); }
/** * Allows adding data to a row before processing it. * * For example, filter module used to store filter format settings in the * variables table which now needs to be inside the filter format config * file. So, it needs to be added here. * * hook_migrate_MIGRATION_ID_prepare_row() is also available. * * @ingroup migration */ function hook_migrate_prepare_row(Row $row, MigrateSourceInterface $source, MigrationInterface $migration) { if ($migration->id() == 'd6_filter_formats') { $value = $source->getDatabase()->query('SELECT value FROM {variable} WHERE name = :name', array(':name' => 'mymodule_filter_foo_' . $row->getSourceProperty('format')))->fetchField(); if ($value) { $row->setSourceProperty('settings:mymodule:foo', unserialize($value)); } } }
/** * {@inheritdoc} */ public function processCckFieldValues(MigrationInterface $migration, $field_name, $data) { $process = ['plugin' => 'iterator', 'source' => $field_name, 'process' => ['value' => 'video_url']]; $migration->mergeProcessOfProperty($field_name, $process); }
/** * {@inheritdoc} */ public function processCckFieldValues(MigrationInterface $migration, $field_name, $data) { $process = ['plugin' => 'd6_cck_file', 'source' => $field_name]; $migration->mergeProcessOfProperty($field_name, $process); }
/** * {@inheritdoc} */ public function processCckFieldValues(MigrationInterface $migration, $field_name, $data) { $process = ['plugin' => 'iterator', 'source' => $field_name, 'process' => ['target_id' => 'fid', 'alt' => 'alt', 'title' => 'title', 'width' => 'width', 'height' => 'height']]; $migration->mergeProcessOfProperty($field_name, $process); }
/** * Helper method to create an entity revision destination with mock services. * * @see \Drupal\Tests\migrate\Unit\Destination\EntityRevision * * @param $configuration * Configuration for the destination. * @param string $plugin_id * The plugin id. * @param array $plugin_definition * The plugin definition. * * @return \Drupal\Tests\migrate\Unit\destination\EntityRevision * Mocked destination. */ protected function getEntityRevisionDestination(array $configuration = [], $plugin_id = 'entity_revision', array $plugin_definition = []) { return new EntityRevision($configuration, $plugin_id, $plugin_definition, $this->migration->reveal(), $this->storage->reveal(), [], $this->entityManager->reveal(), $this->fieldTypeManager->reveal()); }
/** * {@inheritdoc} */ public function processFieldInstance(MigrationInterface $migration) { $process = ['plugin' => 'static_map', 'source' => 'instance_settings/title', 'bypass' => TRUE, 'map' => ['disabled' => DRUPAL_DISABLED, 'optional' => DRUPAL_OPTIONAL, 'required' => DRUPAL_REQUIRED]]; $migration->mergeProcessOfProperty('settings/title', $process); }