Right now there's no example on how to accomplish this.

I'm willing to write it as long as I get some guidance as to how it work.

Comments

sea4’s picture

this would be great!

mikeryan’s picture

Component: Migrate Extras Features » Documentation
Category: feature » task
Status: Active » Needs work

Well, I recently had my first shot at migrating webform submissions (note there is no migration path currently implemented for webforms themselves, I manually rebuilt them). Here's a class derived from migrate_d2d's DrupalMigration (this was a D6-to-D7 deal), scrubbed of some customer-specific stuff, with extra comments for the general audience. It's key to note that this is the migration for the submissions to a single webform.

class ExampleWebformMigration extends DrupalMigration {
  public function __construct($arguments) {
    parent::__construct($arguments);
    $this->dependencies[] = 'User';

    // These are the form_key values from webform_component - never got around to giving them nice labels
    $fields = array(
      'username' => 'username',
      'first_name' => 'first_name',
      'last_name' => 'last_name',
      'email_address' => 'email_address',
      'date_of_event' => 'date_of_event',
      'city__state' => 'city__state',
      'number_of_tickets_purchased' => 'number_of_tickets_purchased',
      'guests' => 'guests',
    );
    $this->source = new MigrateSourceSQL($this->query(), $fields, NULL,
      array('map_joinable' => FALSE));
    // Find the destination webform by title
    $nodes = node_load_multiple(array(), array('type' => 'webform',
      'title' => 'Example Sign Up'));
    $node = reset($nodes);
    $this->destination = new MigrateDestinationWebformSubmission($node);
    $this->map = new MigrateSQLMap($this->machineName,
       array(
         'sid' => array('type' => 'int',
                        'unsigned' => TRUE,
                        'not null' => TRUE,
                        'description' => 'Webform submission ID',
                        'alias' => 's',
                       ),
       ),
       MigrateDestinationWebformSubmission::getKeySchema()
    );

    $this->addSimpleMappings(array('submitted', 'remote_addr'));
    $this->addFieldMapping('uid', 'uid')
         ->sourceMigration('User');
    $this->addFieldMapping('is_draft')
         ->defaultValue(0);
    // On the destination side we get these unintuitive form keys
    $this->addFieldMapping('data_new_1346960272729', 'username');
    $this->addFieldMapping('data_new_1346960598775', 'first_name');
    $this->addFieldMapping('data_new_1346960634561', 'last_name');
    $this->addFieldMapping('data_new_1346960673212', 'email_address');
    $this->addFieldMapping('data_new_1346960718925', 'date_of_event');
    $this->addFieldMapping('data_new_1346961121117', 'city__state');
    $this->addFieldMapping('data_new_1346961266027', 'number_of_tickets_purchased');
    $this->addFieldMapping('data_new_1346961351618', 'guests');

    $this->addUnmigratedDestinations(array(
      'data_new_1346959782966',
      'sid',
    ));
  }

  protected function query() {
    // We're only interested in one webform, with the known legacy nid 8346
    $query = Database::getConnection('default', 'legacy')
             ->select('webform_submissions', 's')
             ->fields('s', array('sid', 'uid', 'submitted', 'remote_addr'))
             ->condition('nid', 8346);
    return $query;
  }

  public function prepareRow($row) {
    $query = Database::getConnection('default', 'legacy')
             ->select('webform_submitted_data', 'd')
             ->fields('d', array('data'))
             ->condition('sid', $row->sid);
    $query->innerJoin('webform_component', 'c', 'd.nid=c.nid AND d.cid=c.cid');
    $query->fields('c', array('form_key'));
    $result = $query->execute();
    foreach ($result as $data_row) {
      $row->{$data_row->form_key} = $data_row->data;
    }
  }
}

Ain't that pretty, but it works.

rooby’s picture

note there is no migration path currently implemented for webforms themselves, I manually rebuilt them

Is this still the case? are we just dealing with submissions here?

Anonymous’s picture

I'm attempting to migrate some webforms that must be done programmatically so I'm going to create some classes to deal with the components and settings. I was able to create a node migration using the migrate_d2d docs, but upon doing so I need to ask a question about the code sample above:

$this->addFieldMapping('data_new_1346960272729', 'username');

Where exactly does that $DEST field get defined? I haven't seen this format in use on any migrate modules. Assuming it is probably a temporary variable but I'm not sure.

In any case, what I'm going to do for my environment is the following:

  • WebformNode migration that extends migrate_d2d (somewhat similar to above)
  • WebformComponent migration to bring the fields across
  • WebformSettings migration to manage what is in the webform table
  • WebformSubmissions migration extending migrate_extras

Anything I'm missing here? It looks like webform_emails, webform_roles, webform_submitted_data and webform_last_download can probably be skipped?

vlad.dancer’s picture

Hi, Ryan Weal.

I haven't seen this format in use on any migrate modules.

You can simply debug this if you inspect MigrateDestinationWebformSubmission, because addFieldMapping() always is about destination object, so MigrateDestinationWebformSubmission has override for public function __construct, here method adds 'data_' prefix to the destination field name.

Anonymous’s picture

@vlad.dancer thanks. I guess it is specific to this component then!

I was able to setup my node migration using migrate_d2d syntax, and I have a custom class that uses MigrateDestinationTable that brings all of the components from the D6 site.

Currently the code is in my custom module package but I may rework it for migrate_extras if people want it. In a few days I will work on the settings migration.

Anonymous’s picture

It's key to note that this is the migration for the submissions to a single webform.

Noticed that note a bit late... going to have to rewrite that migration it seems. It looks like I'll likely roll a new module to contain my migrations for webform.

I also added a WebformEmails and have now written the WebformSettings migration to the code I'm working on. More to come!

rooby’s picture

@Ryan Weal:
You just need to have a separate migration for each webform, same as you might do for dirfferent node types or different field collections etc. They can still be all together in the same module.

My last migration was just users from a spreadsheet and it required about a dozen migrations to get it all in due to profile2, field collection etc.

Anonymous’s picture

@rooby now I have it all done now following the strategy I outlined above. I'm planning to take out the non-generic code this weekend and post the module. It will autodiscover what node types have webforms enabled, migrate all the nodes (with the default D6 fields), all the configuration*, the form components, email destinations, submissions and associated submission data, in addition to any validation configuration you have (from webform_validation module). It grabs the "last downloaded" data too, in case your users were downloading sequential batches since the last time they were on the site. I did it in 3 business days, it has been epic. I really need some sleep.

*for the configuration I didn't get much into converting the tokens beyond ONE example (user email) and if you use others it will warn you and give you an easy path to fix it (either a link directly to where you can update it to the new value, or a request for a patch and a nice switch statement to make that easy).

It does not yet look for tokens embedded in the body text. However, I have code for that from another migration... so feature request.

I'm considering adding a switch in the configuration to allow preserving nodes/component/submission_ids. Right now it allows both after today's updates.

rooby’s picture

Wow, that sounds fantastic and will be great for the migrate suite.

Thanks for the work, I'm sure it will make my life easier at some point.

Anonymous’s picture

Ok, a sandbox is available! https://drupal.org/sandbox/weal/2115619

  • there is no settings page yet, so the secondary database key should ideally be 'd6' until I can ready a patch
  • currently it is locked to webform node type, but config is in an easy array structure so probably easy enough to deal with for now
  • Users probably won't be referenced correctly as that will be a configuration setting to tie into migrate_d2d's wizard
Anonymous’s picture

Ok, it is a real module now: https://drupal.org/project/migrate_webform

You will need to configure a secondary DB in settings.php, go to "migrate webform config", put the key of the db there, then go to migrate > config page and "re-register statically-defined classes" to get it to work.

Config is pretty rough and mostly borrowed from commerce_migrate_ubercart which I have a big patch ready to support the 2.6 branch of migrate. Maybe I can figure out how to get it working within the migrate_d2d wizard eventually...

solideogloria’s picture

Issue summary: View changes
Status: Needs work » Closed (outdated)
solideogloria’s picture