5 * Code For D6 to D7 field update.
7 * Modules can implement hook_content_migrate_field_alter()
8 * and hook_content_migrate_instance_alter()
10 define('CONTENT_DB_STORAGE_PER_FIELD', 0);
11 define('CONTENT_DB_STORAGE_PER_CONTENT_TYPE', 1);
14 * Implements hook_menu().
16 function content_migrate_menu() {
18 $items['admin/structure/content_migrate'] = array(
19 'title' => 'Migrate fields',
20 'description' => 'Migrate field settings and data from the Drupal 6 version to the Drupal 7 version.',
21 'page callback' => 'drupal_get_form',
22 'page arguments' => array('content_migrate_select'),
23 'access arguments' => array('administer content types'),
24 'file' => 'content_migrate.admin.inc',
31 * Create a D7-style field array from data stored
32 * in the D6 content field tables.
35 * Optionally request only a specific field name.
37 function content_migrate_get_field_values($field_name = NULL
) {
38 $field_values = &drupal_static(__FUNCTION__
);
39 if (!is_array($field_values)) {
40 $field_values = array();
42 if (empty($field_values) && db_table_exists('content_node_field')) {
43 $field_values = array();
44 $query = db_select('content_node_field', 'nf', array('fetch' => PDO
::FETCH_ASSOC
));
45 $node_instance_alias = $query->join('content_node_field_instance', 'ni', 'ni.field_name=nf.field_name');
47 ->fields($node_instance_alias, array('widget_type'))
51 foreach ($result as
$row) {
54 // All Drupal 6 fields were attached to nodes.
55 $field_value['entity_types'] = array('node');
57 $field_value['cardinality'] = $field_value['multiple'] != 1 ?
$field_value['multiple'] : FIELD_CARDINALITY_UNLIMITED
;
59 // We need column information for the old table.
60 $field_value['columns'] = unserialize($field_value['db_columns']);
63 $default_settings = field_info_field_settings($row['type']);
64 $field_value['settings'] = array_merge($default_settings, unserialize($field_value['global_settings']));
66 unset($field_value['multiple'], $field_value['global_settings'], $field_value['required'], $field_value['db_columns']);
68 // Let modules change these values.
69 drupal_alter('content_migrate_field', $field_value);
71 // We left the widget type in the $field_value so modules
72 // could adjust the field based on that information.
73 // Needed so optionwidgets can change the field type
74 // from text or numeric to list.
75 unset($field_value['widget_type'], $field_value['allowed_values_php']);
77 // We retain $field_value['columns'] and $field_value['db_storage']
78 // even though they are not used or different in D7
79 // so we can find the old table information.
81 // Add field definiation to $field_values array.
82 $field_values[$field_value['field_name']] = $field_value;
85 if (!empty($field_name)) {
86 return $field_values[$field_name];
92 * Create a D7-style instance array from data stored
93 * in the D6 content field tables.
96 * Optionally request only instances of a specific bundle.
98 * Optionally request only instances of a specific field_name.
100 function content_migrate_get_instance_values($bundle = NULL
, $field_name = NULL
) {
101 $instance_values = &drupal_static(__FUNCTION__
);
103 if (empty($instance_values) && db_table_exists('content_node_field_instance')) {
104 $instance_values = array();
105 $query = db_select('content_node_field_instance', 'ni', array('fetch' => PDO
::FETCH_ASSOC
));
106 $node_field_alias = $query->join('content_node_field', 'nf', 'ni.field_name=nf.field_name');
109 ->fields($node_field_alias, array('required'))
110 ->orderBy('label', 'ASC')
113 foreach ($result as
$row) {
114 $instance_value = $row;
116 // The instance has the same module as the field,
117 // not the widget. May have been altered
118 // from the original values, so get the altered
120 $field_value = content_migrate_get_field_values($row['field_name']);
121 $instance_value['module'] = $field_value['module'];
123 // All Drupal 6 instances were attached to nodes.
124 $instance_value['entity_type'] = 'node';
126 // Unserialize arrays.
127 foreach (array('widget_settings', 'display_settings', 'global_settings') as
$key) {
128 $instance_value[$key] = (!empty($instance_value[$key])) ?
(array) unserialize($instance_value[$key]) : array();
131 // Build instance values.
132 $instance_value['bundle'] = $instance_value['type_name'];
133 $instance_value['active'] = $instance_value['widget_active'];
134 $instance_value['default_value'] = $instance_value['widget_settings']['default_value'];
136 // Core does not support this, but retain it so
137 // another module can do something with it
139 if (isset($instance_value['widget_settings']['default_value_php'])) {
140 $instance_value['settings']['default_value_php'] = $instance_value['widget_settings']['default_value_php'];
143 // Build widget values.
144 $instance_value['widget'] = array();
146 // TODO Some widget types have been renamed in D7.
147 $instance_value['widget']['type'] = $instance_value['widget_type'];
148 $instance_value['widget']['weight'] = $instance_value['weight'];
149 $instance_value['widget']['module'] = $instance_value['widget_module'];
151 $default_settings = field_info_widget_settings($field_value['type']);
152 $instance_value['widget']['settings'] = array_merge($default_settings, $instance_value['widget_settings']);
154 // Build display values.
155 $instance_value['display'] = $instance_value['display_settings'];
156 $label = $instance_value['display_settings']['label'];
157 foreach ($instance_value['display_settings'] as
$context => $settings) {
159 // @TODO Multigroup fields have some unexpected elements, we need to work out what should happen to them.
160 if ($context == 'parent' || $context == 'weight') {
163 $instance_value['display'][$context]['label'] = $label['format'];
165 // The format used in D6 may not match the formatter in D7.
166 // Fix it using drupal_alter().
167 $instance_value['display'][$context]['type'] = $settings['format'];
168 $instance_value['display'][$context]['settings'] = field_info_formatter_settings($settings['format']);
172 // Unset unneeded values.
173 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']);
175 // Unset some values that don't exist on all fields.
176 if (isset($instance_value['widget']['settings']['default_value'])) unset($instance_value['widget']['settings']['default_value']);
177 if (isset($instance_value['widget']['settings']['default_value_php'])) unset($instance_value['widget']['settings']['default_value_php']);
179 // Let modules change these values.
180 drupal_alter('content_migrate_instance', $instance_value);
182 // Get rid of this value once CCK or some other module has handled it.
183 if (isset($instance_value['settings']['default_value_php'])) unset($instance_value['settings']['default_value_php']);
185 // Add instance information to instance array.
186 $instance_values['instances'][$instance_value['bundle']][$instance_value['field_name']] = $instance_value;
187 $instance_values['fields'][$instance_value['field_name']][$instance_value['bundle']] = $instance_value;
191 if (!empty($bundle)) {
192 if (!empty($field_name)) {
193 return $instance_values['instances'][$bundle][$field_name];
196 return $instance_values['instances'][$bundle];
199 elseif (!empty($field_name)) {
200 return $instance_values['fields'][$field_name];
202 return $instance_values;
206 * Helper function for finding the table name
207 * used to store the D6 field data.
209 * @param $field_value
210 * @param $instance_value
212 function content_migrate_old_table($field_value, $instance_value) {
213 $storage = content_migrate_storage_type($field_value);
215 case CONTENT_DB_STORAGE_PER_CONTENT_TYPE
:
216 $name = $instance_value['bundle'];
217 return "content_type_$name";
218 case CONTENT_DB_STORAGE_PER_FIELD
:
219 $name = $field_value['field_name'];
220 return "content_$name";
225 * Helper function for finding the type of table
226 * used for storing the D6 field data.
228 * @param $field_value
229 * @param $instance_value
231 function content_migrate_storage_type($field_value) {
232 $storage = CONTENT_DB_STORAGE_PER_CONTENT_TYPE
;
233 if (isset($field_value['db_storage'])) {
234 return $field_value['db_storage'];
236 elseif ($field_value['cardinality'] > 0 || $field_value['cardinality'] == FIELD_CARDINALITY_UNLIMITED
) {
237 $storage = CONTENT_DB_STORAGE_PER_FIELD
;
240 $instance_values = content_migrate_get_instance_values(NULL
, $field_value['field_name']);
241 if (count($instance_values) > 1) {
242 $storage = CONTENT_DB_STORAGE_PER_FIELD
;
249 * Helper function to find the table for a
254 function content_migrate_new_table($field) {
255 if (empty($field['storage']['details'])) {
256 return 'field_data_'.
$field['field_name'];
258 $data = $field['storage']['details']['sql'][FIELD_LOAD_CURRENT
];
262 function content_migrate_new_revision($field) {
263 if (empty($field['storage']['details'])) {
264 return 'field_revision_'.
$field['field_name'];
266 $data = $field['storage']['details']['sql'][FIELD_LOAD_REVISION
];
271 * Helper function for finding the column names
272 * used for storing the D6 field data.
274 * @param $field_value
275 * @param $instance_value
277 function content_migrate_old_columns($field_value, $instance_value) {
279 foreach ($field_value['columns'] as
$col => $values) {
280 $columns[] = $field_value['field_name'] .
'_'.
$col;
285 * Helper function for figuring out column names
286 * to be used when storing D7 field data.
288 * @param unknown_type $field
291 function content_migrate_new_columns($field) {
293 if (empty($field['storage']['details'])) {
294 foreach ($field['columns'] as
$col => $values) {
295 $columns[] = $field['field_name'] .
'_'.
$col;
300 foreach ($field['storage']['details']['sql'][FIELD_LOAD_CURRENT
] as
$table => $cols) {
301 foreach ($cols as
$col) {
310 * Implements hook_content_migrate_field_alter().
312 * Use this to tweak the conversion of field settings
313 * from the D6 style to the D7 style for specific
314 * situations not handled by basic conversion,
315 * as when field types or settings are changed.
317 * $field_value['widget_type'] is available to
318 * see what widget type was originally used.
320 function content_migrate_content_migrate_field_alter(&$field_value) {
322 switch ($field_value['type']) {
325 // The max_length field can no longer be empty
326 // or it will create a SQL error.
327 if (empty($field_value['settings']['max_length'])) {
328 $field_value['settings']['max_length'] = 255;
331 // Text fields using optionwidgets are
333 switch ($field_value['widget_type']) {
334 case
'optionwidgets_buttons':
335 case
'optionwidgets_select':
336 $field_value['type'] = 'list_text';
337 $field_value['module'] = 'list';
339 case
'optionwidgets_onoff':
340 $field_value['type'] = 'list_boolean';
341 $field_value['module'] = 'list';
343 case
'text_textarea':
344 $field_value['type'] = 'text_long';
345 unset($field_value['settings']['max_length']);
350 case
'number_integer':
351 case
'number_decimal':
354 // Changed name of setting from 'decimal' to
355 // 'decimal_separator'.
356 if (isset($field_value['settings']['decimal'])) {
357 $field_value['settings']['decimal_separator'] = $field_value['settings']['decimal'];
358 unset($field_value['settings']['decimal']);
360 // Add a decimal_separator setting to floats.
361 if ($field_value['type'] == 'number_float') {
362 $field_value['settings']['decimal_separator'] = '.';
365 // Number fields using optionwidgets are
367 switch ($field_value['widget_type']) {
368 case
'optionwidgets_buttons':
369 case
'optionwidgets_select':
370 $field_value['type'] = 'list_number';
371 $field_value['module'] = 'list';
373 case
'optionwidgets_onoff':
374 $field_value['type'] = 'list_boolean';
375 $field_value['module'] = 'list';
383 * Implements hook_content_migrate_instance_alter().
385 * Use this to tweak the conversion of instance or widget settings
386 * from the D6 style to the D7 style for specific
387 * situations not handled by basic conversion, as when
388 * formatter or widget names or settings are changed.
390 function content_migrate_content_migrate_instance_alter(&$instance_value) {
391 //$field = content_migrate_get_field_values($instance_value['field_name']);
393 switch ($instance_value['widget']['module']) {
394 // Optionswidgets module became Options module
395 // and widget type names changed.
396 case ('optionwidgets'):
398 'optionwidgets_select' => 'options_select',
399 'optionwidgets_buttons' => 'options_buttons',
400 'optionwidgets_onoff' => 'options_onoff',
402 $instance_value['widget']['module'] = 'options';
403 $instance_value['widget']['type'] = strtr($instance_value['widget']['type'], $replace);
407 switch ($instance_value['module']) {
409 // The formatter names changed, all are prefixed
411 foreach ($instance_value['display'] as
$context => $settings) {
412 $instance_value['display'][$context]['type'] = 'text_'.
$settings['type'];
417 // The number formatters and formatter settings
420 'unformatted' => 'number_unformatted',
421 'default' => 'number_decimal',
422 'us_0' => 'number_integer',
423 'us_1' => 'number_decimal',
424 'us_2' => 'number_decimal',
425 'be_0' => 'number_integer',
426 'be_1' => 'number_decimal',
427 'be_2' => 'number_decimal',
428 'fr_0' => 'number_integer',
429 'fr_1' => 'number_decimal',
430 'fr_2' => 'number_decimal',
432 $new_settings = array(
434 'thousand_separator' => '',
435 'decimal_separator' => '.',
437 'prefix_suffix' => TRUE
,
440 'thousand_separator' => ',',
441 'decimal_separator' => '.',
443 'prefix_suffix' => TRUE
,
446 'thousand_separator' => ',',
447 'decimal_separator' => '.',
449 'prefix_suffix' => TRUE
,
452 'thousand_separator' => ',',
453 'decimal_separator' => '.',
455 'prefix_suffix' => TRUE
,
458 'thousand_separator' => '',
459 'decimal_separator' => ',',
461 'prefix_suffix' => TRUE
,
464 'thousand_separator' => '.',
465 'decimal_separator' => ',',
467 'prefix_suffix' => TRUE
,
470 'thousand_separator' => '.',
471 'decimal_separator' => ',',
473 'prefix_suffix' => TRUE
,
476 'thousand_separator' => '',
477 'decimal_separator' => ', ',
479 'prefix_suffix' => TRUE
,
482 'thousand_separator' => ' ',
483 'decimal_separator' => ', ',
485 'prefix_suffix' => TRUE
,
488 'thousand_separator' => ' ',
489 'decimal_separator' => ', ',
491 'prefix_suffix' => TRUE
,
494 foreach ($instance_value['display'] as
$context => $settings) {
495 $instance_value['display'][$context]['type'] = $new_type[$settings['type']];
496 $instance_value['display'][$context]['settings'] = $new_settings[$settings['type']];