'Migrate fields', 'description' => 'Migrate field settings and data from the Drupal 6 version to the Drupal 7 version.', 'page callback' => 'drupal_get_form', 'page arguments' => array('content_migrate_select'), 'access arguments' => array('administer content types'), 'file' => 'content_migrate.admin.inc', ); return $items; } /** * Create a D7-style field array from data stored * in the D6 content field tables. * * @param $field_name * Optionally request only a specific field name. */ function content_migrate_get_field_values($field_name = NULL) { $field_values = &drupal_static(__FUNCTION__); if (!is_array($field_values)) { $field_values = array(); } if (empty($field_values) && db_table_exists('content_node_field')) { $field_values = array(); $query = db_select('content_node_field', 'nf', array('fetch' => PDO::FETCH_ASSOC)); $node_instance_alias = $query->join('content_node_field_instance', 'ni', 'ni.field_name=nf.field_name'); $result = $query ->fields($node_instance_alias, array('widget_type')) ->fields('nf') ->execute(); foreach ($result as $row) { $field_value = $row; // All Drupal 6 fields were attached to nodes. $field_value['entity_types'] = array('node'); $field_value['cardinality'] = $field_value['multiple'] != 1 ? $field_value['multiple'] : FIELD_CARDINALITY_UNLIMITED; // We need column information for the old table. $field_value['columns'] = unserialize($field_value['db_columns']); // Field settings. $default_settings = field_info_field_settings($row['type']); $field_value['settings'] = array_merge($default_settings, unserialize($field_value['global_settings'])); unset($field_value['multiple'], $field_value['global_settings'], $field_value['required'], $field_value['db_columns']); // Let modules change these values. drupal_alter('content_migrate_field', $field_value); // We left the widget type in the $field_value so modules // could adjust the field based on that information. // Needed so optionwidgets can change the field type // from text or numeric to list. unset($field_value['widget_type'], $field_value['allowed_values_php']); // We retain $field_value['columns'] and $field_value['db_storage'] // even though they are not used or different in D7 // so we can find the old table information. // Add field definiation to $field_values array. $field_values[$field_value['field_name']] = $field_value; } } if (!empty($field_name)) { return $field_values[$field_name]; } return $field_values; } /** * Create a D7-style instance array from data stored * in the D6 content field tables. * * @param $bundle * Optionally request only instances of a specific bundle. * @param $field_name * Optionally request only instances of a specific field_name. */ function content_migrate_get_instance_values($bundle = NULL, $field_name = NULL) { $instance_values = &drupal_static(__FUNCTION__); if (empty($instance_values) && db_table_exists('content_node_field_instance')) { $instance_values = array(); $query = db_select('content_node_field_instance', 'ni', array('fetch' => PDO::FETCH_ASSOC)); $node_field_alias = $query->join('content_node_field', 'nf', 'ni.field_name=nf.field_name'); $result = $query ->fields('ni') ->fields($node_field_alias, array('required')) ->orderBy('label', 'ASC') ->execute(); foreach ($result as $row) { $instance_value = $row; // The instance has the same module as the field, // not the widget. May have been altered // from the original values, so get the altered // field values. $field_value = content_migrate_get_field_values($row['field_name']); $instance_value['module'] = $field_value['module']; // All Drupal 6 instances were attached to nodes. $instance_value['entity_type'] = 'node'; // Unserialize arrays. foreach (array('widget_settings', 'display_settings', 'global_settings') as $key) { $instance_value[$key] = (!empty($instance_value[$key])) ? (array) unserialize($instance_value[$key]) : array(); } // Build instance values. $instance_value['bundle'] = $instance_value['type_name']; $instance_value['active'] = $instance_value['widget_active']; $instance_value['default_value'] = $instance_value['widget_settings']['default_value']; // Core does not support this, but retain it so // another module can do something with it // in drupal_alter. if (isset($instance_value['widget_settings']['default_value_php'])) { $instance_value['settings']['default_value_php'] = $instance_value['widget_settings']['default_value_php']; } // Build widget values. $instance_value['widget'] = array(); // TODO Some widget types have been renamed in D7. $instance_value['widget']['type'] = $instance_value['widget_type']; $instance_value['widget']['weight'] = $instance_value['weight']; $instance_value['widget']['module'] = $instance_value['widget_module']; $default_settings = field_info_widget_settings($field_value['type']); $instance_value['widget']['settings'] = array_merge($default_settings, $instance_value['widget_settings']); // Build display values. $instance_value['display'] = $instance_value['display_settings']; $label = $instance_value['display_settings']['label']; foreach ($instance_value['display_settings'] as $context => $settings) { // @TODO Multigroup fields have some unexpected elements, we need to work out what should happen to them. if ($context == 'parent' || $context == 'weight') { continue; } $instance_value['display'][$context]['label'] = $label['format']; // The format used in D6 may not match the formatter in D7. // Fix it using drupal_alter(). $instance_value['display'][$context]['type'] = $settings['format']; $instance_value['display'][$context]['settings'] = field_info_formatter_settings($settings['format']); } // Unset unneeded values. unset($instance_value['type_name'], $instance_value['global_settings'], $instance_value['widget_settings'], $instance_value['display_settings'], $instance_value['widget_module'], $instance_value['widget_active']); // Unset some values that don't exist on all fields. if (isset($instance_value['widget']['settings']['default_value'])) unset($instance_value['widget']['settings']['default_value']); if (isset($instance_value['widget']['settings']['default_value_php'])) unset($instance_value['widget']['settings']['default_value_php']); // Let modules change these values. drupal_alter('content_migrate_instance', $instance_value); // Get rid of this value once CCK or some other module has handled it. if (isset($instance_value['settings']['default_value_php'])) unset($instance_value['settings']['default_value_php']); // Add instance information to instance array. $instance_values['instances'][$instance_value['bundle']][$instance_value['field_name']] = $instance_value; $instance_values['fields'][$instance_value['field_name']][$instance_value['bundle']] = $instance_value; } } if (!empty($bundle)) { if (!empty($field_name)) { return $instance_values['instances'][$bundle][$field_name]; } else { return $instance_values['instances'][$bundle]; } } elseif (!empty($field_name)) { return $instance_values['fields'][$field_name]; } return $instance_values; } /** * Helper function for finding the table name * used to store the D6 field data. * * @param $field_value * @param $instance_value */ function content_migrate_old_table($field_value, $instance_value) { $storage = content_migrate_storage_type($field_value); switch ($storage) { case CONTENT_DB_STORAGE_PER_CONTENT_TYPE : $name = $instance_value['bundle']; return "content_type_$name"; case CONTENT_DB_STORAGE_PER_FIELD : $name = $field_value['field_name']; return "content_$name"; } } /** * Helper function for finding the type of table * used for storing the D6 field data. * * @param $field_value * @param $instance_value */ function content_migrate_storage_type($field_value) { $storage = CONTENT_DB_STORAGE_PER_CONTENT_TYPE; if (isset($field_value['db_storage'])) { return $field_value['db_storage']; } elseif ($field_value['cardinality'] > 0 || $field_value['cardinality'] == FIELD_CARDINALITY_UNLIMITED) { $storage = CONTENT_DB_STORAGE_PER_FIELD; } else { $instance_values = content_migrate_get_instance_values(NULL, $field_value['field_name']); if (count($instance_values) > 1) { $storage = CONTENT_DB_STORAGE_PER_FIELD; } } return $storage; } /** * Helper function to find the table for a * D7 field array. * * @param $field */ function content_migrate_new_table($field) { if (empty($field['storage']['details'])) { return 'field_data_'. $field['field_name']; } $data = $field['storage']['details']['sql'][FIELD_LOAD_CURRENT]; return key($data); } function content_migrate_new_revision($field) { if (empty($field['storage']['details'])) { return 'field_revision_'. $field['field_name']; } $data = $field['storage']['details']['sql'][FIELD_LOAD_REVISION]; return key($data); } /** * Helper function for finding the column names * used for storing the D6 field data. * * @param $field_value * @param $instance_value */ function content_migrate_old_columns($field_value, $instance_value) { $columns = array(); foreach ($field_value['columns'] as $col => $values) { $columns[] = $field_value['field_name'] .'_'. $col; } return $columns; } /** * Helper function for figuring out column names * to be used when storing D7 field data. * * @param unknown_type $field * @return unknown */ function content_migrate_new_columns($field) { $columns = array(); if (empty($field['storage']['details'])) { foreach ($field['columns'] as $col => $values) { $columns[] = $field['field_name'] .'_'. $col; } return $columns; } else { foreach ($field['storage']['details']['sql'][FIELD_LOAD_CURRENT] as $table => $cols) { foreach ($cols as $col) { $columns[] = $col; } } return $columns; } } /** * Implements hook_content_migrate_field_alter(). * * Use this to tweak the conversion of field settings * from the D6 style to the D7 style for specific * situations not handled by basic conversion, * as when field types or settings are changed. * * $field_value['widget_type'] is available to * see what widget type was originally used. */ function content_migrate_content_migrate_field_alter(&$field_value) { switch ($field_value['type']) { case 'text': // The max_length field can no longer be empty // or it will create a SQL error. if (empty($field_value['settings']['max_length'])) { $field_value['settings']['max_length'] = 255; } // Text fields using optionwidgets are // now List fields. switch ($field_value['widget_type']) { case 'optionwidgets_buttons': case 'optionwidgets_select': $field_value['type'] = 'list_text'; $field_value['module'] = 'list'; break; case 'optionwidgets_onoff': $field_value['type'] = 'list_boolean'; $field_value['module'] = 'list'; break; case 'text_textarea': $field_value['type'] = 'text_long'; unset($field_value['settings']['max_length']); break; } break; case 'number_integer': case 'number_decimal': case 'number_float': // Changed name of setting from 'decimal' to // 'decimal_separator'. if (isset($field_value['settings']['decimal'])) { $field_value['settings']['decimal_separator'] = $field_value['settings']['decimal']; unset($field_value['settings']['decimal']); } // Add a decimal_separator setting to floats. if ($field_value['type'] == 'number_float') { $field_value['settings']['decimal_separator'] = '.'; } // Number fields using optionwidgets are // now List fields. switch ($field_value['widget_type']) { case 'optionwidgets_buttons': case 'optionwidgets_select': $field_value['type'] = 'list_number'; $field_value['module'] = 'list'; break; case 'optionwidgets_onoff': $field_value['type'] = 'list_boolean'; $field_value['module'] = 'list'; break; } break; } } /** * Implements hook_content_migrate_instance_alter(). * * Use this to tweak the conversion of instance or widget settings * from the D6 style to the D7 style for specific * situations not handled by basic conversion, as when * formatter or widget names or settings are changed. */ function content_migrate_content_migrate_instance_alter(&$instance_value) { //$field = content_migrate_get_field_values($instance_value['field_name']); switch ($instance_value['widget']['module']) { // Optionswidgets module became Options module // and widget type names changed. case ('optionwidgets'): $replace = array( 'optionwidgets_select' => 'options_select', 'optionwidgets_buttons' => 'options_buttons', 'optionwidgets_onoff' => 'options_onoff', ); $instance_value['widget']['module'] = 'options'; $instance_value['widget']['type'] = strtr($instance_value['widget']['type'], $replace); break; } switch ($instance_value['module']) { case 'text': // The formatter names changed, all are prefixed // with 'text_'. foreach ($instance_value['display'] as $context => $settings) { $instance_value['display'][$context]['type'] = 'text_'. $settings['type']; } break; case 'number': // The number formatters and formatter settings // have changed. $new_type = array( 'unformatted' => 'number_unformatted', 'default' => 'number_decimal', 'us_0' => 'number_integer', 'us_1' => 'number_decimal', 'us_2' => 'number_decimal', 'be_0' => 'number_integer', 'be_1' => 'number_decimal', 'be_2' => 'number_decimal', 'fr_0' => 'number_integer', 'fr_1' => 'number_decimal', 'fr_2' => 'number_decimal', ); $new_settings = array( 'default' => array( 'thousand_separator' => '', 'decimal_separator' => '.', 'scale' => 0, 'prefix_suffix' => TRUE, ), 'us_0' => array( 'thousand_separator' => ',', 'decimal_separator' => '.', 'scale' => 0, 'prefix_suffix' => TRUE, ), 'us_1' => array( 'thousand_separator' => ',', 'decimal_separator' => '.', 'scale' => 1, 'prefix_suffix' => TRUE, ), 'us_2' => array( 'thousand_separator' => ',', 'decimal_separator' => '.', 'scale' => 2, 'prefix_suffix' => TRUE, ), 'be_0' => array( 'thousand_separator' => '', 'decimal_separator' => ',', 'scale' => 0, 'prefix_suffix' => TRUE, ), 'be_1' => array( 'thousand_separator' => '.', 'decimal_separator' => ',', 'scale' => 1, 'prefix_suffix' => TRUE, ), 'be_2' => array( 'thousand_separator' => '.', 'decimal_separator' => ',', 'scale' => 2, 'prefix_suffix' => TRUE, ), 'fr_0' => array( 'thousand_separator' => '', 'decimal_separator' => ', ', 'scale' => 0, 'prefix_suffix' => TRUE, ), 'fr_1' => array( 'thousand_separator' => ' ', 'decimal_separator' => ', ', 'scale' => 1, 'prefix_suffix' => TRUE, ), 'fr_2' => array( 'thousand_separator' => ' ', 'decimal_separator' => ', ', 'scale' => 2, 'prefix_suffix' => TRUE, ), ); foreach ($instance_value['display'] as $context => $settings) { $instance_value['display'][$context]['type'] = $new_type[$settings['type']]; $instance_value['display'][$context]['settings'] = $new_settings[$settings['type']]; } break; } }