Webform Addressfield Migration

Specs

Version
Drupal 7
Tools
Drush
Webform
Created
12 Jun 2015
Sections
  1. Drush Command

Summary

Often times, the structure of things like content types or webforms need to be changed after data already exists for them on a production site. In this example, an addressfield component was added to a webform to replace a set of regular textfields used to capture the address.

This example shows how to add addressfield components to an existing webform, and update all of that webform's submissions by mapping data from the original textfields to the new addressfield component. This will not be an exact fit for anyone else's project and is meant only as an example on which to base your own work.

Code

1. Drush Command

MODULE_NAME.drush.inc
          
/**
 * Implements hook_drush_command().
 */
function MODULE_NAME_drush_command() {

  $items['update1'] = array(
    'description' => t('Process update 1'),
    'aliases' => array('updr'),
    'callback' => 'MODULE_NAME_drush_update_1',
    'options' => array(
      'number' => t('The update number to run.'),
    ),
  );

  return $items;
}

/*
 * 
 */
function MODULE_NAME_drush_update_1() {

  // nids of webforms to add addressfield component to
  $nids = array(1, 2, 3);
    
  // first add address component to webforms
  foreach ($nids as $nid) {
    $node = node_load($nid);
    $addressfield_exists = FALSE;
    $address_weight = 2; // best guess at weight if it can't be pulled from address_1 component about 6 lines down
    foreach ($node->webform['components'] as $key => $data) {
      if (($data['type'] == 'addressfield') || ($data['form_key'] == 'address')) {
        $addressfield_exists = TRUE;
      }
      if (($data['name'] == 'Address 1') || ($data['name'] == 'Address line 1')) {
        $address_weight = $data['weight']; // put address field in same place as old address 1 field by mapping its weight
      }
    }
    
    // only add the component if it does not already exist on the webform
    if ($addressfield_exists == FALSE) {
      $node->webform['components'][] = array(
        'nid' => $node->nid,
        'pid' => 0,
        'form_key' => 'address',
        'name' => t('Address'),
        'type' => 'addressfield',
        'value' => '',
        'extra' => array(
          'available_countries' => array(
            'CA' => 'CA',
            'US' => 'US',
          ),
          'csv_separate' => 1,
          'private' => 0,
          'wrapper_classes' => '',
          'css_classes' => '',
          'title_display' => 0,
          'attributes' => array(),
          'description' => '',
        ),
        'required' => 1,
        'weight' => $address_weight,
        'page_num' => 1,
      );
      node_save($node);
    }
  }
  
  // now migrate old submission data to new addressfield component
  module_load_include('inc', 'webform', 'includes/webform.submissions');
  $submissions = webform_get_submissions(array('nid' => $nids));
  
  foreach ($submissions as $submission) {
    // first find CID of address field
    $node = node_load($submission->nid);
    
    // Get component IDs based on field types and labels
    $cids = array();
    foreach ($node->webform['components'] as $cid => $component) {
      if ($component['name'] == 'Address') {
        $cids['address'] = $component['cid'];
      }
      if (($component['name'] == 'Address 1') || ($component['name'] == 'Address line 1')) {
        $cids['address_1'] = $component['cid'];
      }
      if (($component['name'] == 'Address 2') || ($component['name'] == 'Address line 2')) {
        $cids['address_2'] = $component['cid'];
      }
      if ($component['name'] == 'Address 3') {
        $cids['address_3'] = $component['cid'];
      }
      if ($component['name'] == 'City') {
        $cids['city'] = $component['cid'];
      }
      if (($component['name'] == 'State/Province') || ($component['name'] == 'State')) {
        $cids['state'] = $component['cid'];
      }
      if (($component['name'] == 'Zip/Postal Code')) {
        $cids['zip'] = $component['cid'];
      }
    }
    
    // $cids is an array of component IDs for the old address text/select fields, and of the new
    // addressfield.
    if (empty($submission->data[$cids['address']][0]['thoroughfare']) && empty($submission->data[$cids['address']][0]['administrative_area']) && empty($submission->data[$cids['address']][0]['country'])) {
      $submission->data[$cids['address']][0]['thoroughfare'] = $submission->data[$cids['address_1']][0]; // address 1
      $submission->data[$cids['address']][0]['premise'] = $submission->data[$cids['address_2']][0]; // address 2
      // add address 3 field conditionally if it exists
      if (!empty($cids['address_3']) && !empty($submission->data[$cids['address_3']][0])) {
        $submission->data[$cids['address']][0]['premise'] .= $submission->data[$cids['address_3']][0];
      }
      $submission->data[$cids['address']][0]['locality'] = $submission->data[$cids['city']][0]; // city
      $submission->data[$cids['address']][0]['administrative_area'] = $submission->data[$cids['state']][0]; // state
      $submission->data[$cids['address']][0]['postal_code'] = $submission->data[$cids['zip']][0]; // zip
      $submission->data[$cids['address']][0]['country'] = 'US'; // 2 digit country code
      $submission->data[$cids['address']][0] = serialize($submission->data[$cids['address']][0]);
     
      db_delete('webform_submitted_data')
            ->condition('sid', $submission->sid)
            ->execute();
     
      foreach ($submission->data as $cid => $values) {
        foreach ($values as $delta => $value) {
          $data = array(
            'nid' => $node->webform['nid'],
            'sid' => $submission->sid,
            'cid' => $cid,
            'no' => $delta,
            'data' => is_null($value) ? '' : $value,
          );
          drupal_write_record('webform_submitted_data', $data);
        }
      }
      
    }
  }
}
          
          

Comments

Placeholder: I'll extend node comments with ajax and other functionality here.