=== modified file 'modules/system/system.install' --- modules/system/system.install 2009-08-29 11:00:03 +0000 +++ modules/system/system.install 2009-09-05 13:49:06 +0000 @@ -2459,6 +2459,130 @@ } /** + * Change profile.module fields into Field API fields. + */ +function system_update_7038() { + $ret = array(); + $fields = array(); + + if (!db_table_exists('profile_field')) { + return $ret; + } + // Get all profile fields. + $old_fields = db_query('SELECT * FROM {profile_field} ORDER BY category, weight'); + + foreach ($old_fields as $old_field) { + // Create new fields using the field API. + $field = array( + 'field_name' => strtolower(str_replace('-', '_', $old_field->name)), + 'cardinality' => 1, + ); + + // Create field instance on the user bundle. + $instance = array( + 'field_name' => $field['field_name'], + 'bundle' => 'user', + 'description' => $old_field->explanation, + 'label' => $old_field->title, + 'required' => $old_field->required, + 'widget' => array( + 'weight' => $old_field->weight, + ), + 'display' => array( + 'full' => array( + 'weight' => $old_field->weight, + ), + ), + 'settings' => array( + 'user_register' => $old_field->register, + ), + ); + + switch ($old_field->type) { + case 'textfield': + $field['type'] = 'text'; + $instance['widget']['type'] = 'text_textfield'; + + // Only allow plain text. + $instance['settings']['text_processing'] = 0; + break; + + case 'textarea': + $field['type'] = 'text_long'; + $instance['widget']['type'] = 'text_textarea'; + // Use the default text format. + $instance['settings']['text_processing'] = variable_get('filter_default_format', 1); + break; + + case 'checkbox': + $field['type'] = 'list_boolean'; + $instance['widget']['type'] = 'options_onoff'; + $field['settings']['allowed_values'] = "0\n1|" . $old_field->title; + break; + + case 'selection': + $field['type'] = 'list_text'; + $instance['widget']['type'] = 'options_select'; + $field['settings']['allowed_values'] = $old_field->options; + break; + + case 'list': + $field['type'] = 'text'; + $field['cardinality'] = FIELD_CARDINALITY_UNLIMITED; + break; + + case 'date': + $ret[] = array('success' => TRUE, 'query' => 'To migrate date fields from the profile module, install the date module.'); + continue 2; + + case 'url': + $ret[] = array('success' => TRUE, 'query' => 'To migrate URL fields from the profile module, install the link module.'); + continue 2; + } + + try { + field_create_field($field); + field_create_instance($instance); + $fields[$old_field->fid] = $field; + } + catch (Exception $e) { + $ret[] = array('success' => FALSE, 'query' => t('There was a problem creating field %label: @message.', array('%label' => $instance['label'], '@message' => $e->getMessage()))); + } + } + + // Get old field values from the profile.module table. + $results = db_query('SELECT uid, fid, value FROM {profile_value} WHERE value IS NOT NULL'); + + $accounts = array(); + foreach ($results as $result) { + $field_name = $fields[$result->fid]['field_name']; + $accounts[$result->uid]['uid'] = $result->uid; + + if ($fields[$result->fid]['type'] == 'text' && $fields[$result->fid]['cardinality'] == FIELD_CARDINALITY_UNLIMITED) { + $values = array_filter(array_map('trim', preg_split("/[,\n\r]/", $result->value))); + $delta = 0; + foreach ($values as $value) { + $accounts[$result->uid][$field_name][FIELD_LANGUAGE_NONE][$delta]['value'] = $value; + $delta++; + } + } + else { + $accounts[$result->uid][$field_name][FIELD_LANGUAGE_NONE][0]['value'] = $result->value; + } + } + + // Set new field values using the field API. + foreach ($accounts as $account) { + $account = (object) $account; + field_attach_update('user', $account); + } + + $ret[] = array('success' => TRUE, 'query' => 'The profile module has been replaced by the new Fields UI. For additional functionality such as adding fields to the registration form, install the Retro Profile module.'); + + return $ret; +} + +/** * @} End of "defgroup updates-6.x-to-7.x" * The next series of updates should start at 8000. */ === modified file 'modules/system/system.test' --- modules/system/system.test 2009-09-01 17:00:02 +0000 +++ modules/system/system.test 2009-09-05 14:50:52 +0000 @@ -1227,3 +1227,248 @@ $this->assertFalse(strcmp($generated['[node:title]'], $node->title), t('Unsanitized token generated properly.')); } } + +class SystemUpdateTestCase extends DrupalWebTestCase { + /** + * Implement getInfo(). + */ + public static function getInfo() { + return array( + 'name' => 'Update path', + 'description' => 'Test the update path from older version of Drupal.', + 'group' => 'System' + ); + } + + function testSystemUpdate7038() { + // Create a user and an array for field_attach_load(). + $profile_user = $this->drupalCreateUser(); + + // Create some old profile field data to test the update. + $old_schema = $this->profileSchema(); + db_create_table($ret, 'profile_field', $old_schema['profile_field']); + db_create_table($ret, 'profile_value', $old_schema['profile_value']); + + $old_fields['textfield'] = array( + 'title' => $this->randomName(), + 'name' => $this->randomName(), + 'explanation' => $this->randomName(50), + 'category' => $this->randomName(), + 'page' => NULL, + 'type' => 'textfield', + 'weight' => rand(-10, 10), + 'required' => 1, + 'register' => 1, + 'visibility' => 0, + 'autocomplete' => 0, + 'options' => NULL, + ); + $old_fields['textarea'] = array( + 'title' => $this->randomName(), + 'name' => $this->randomName(), + 'type' => 'textarea', + 'required' => 0, + ); + $old_fields['checkbox'] = array( + 'title' => $this->randomName(), + 'name' => $this->randomName(), + 'type' => 'checkbox', + ); + + $fid = 1; + foreach ($old_fields as $field_name => $old_field) { + // Create the configuration for the profile.module field. + $old_field['fid'] = $fid; + db_insert('profile_field')->fields($old_field)->execute(); + + // Set profile.module field values for $profile_user. + $old_field_value = array( + 'fid' => $fid, + 'uid' => $profile_user->uid, + ); + switch ($old_field['type']) { + case 'textfield': + case 'textarea': + $old_field_value['value'] = $this->randomName(); + break; + + case 'checkbox': + $old_field_value['value'] = rand(0, 1); + break; + } + db_insert('profile_value')->fields($old_field_value)->execute(); + $old_fields[$field_name]['value'] = $old_field_value['value']; + $fid++; + } + + // Run the update. + system_update_7038(); + + // Reload the user with the new fields. + $profile_user = user_load($profile_user->uid, TRUE); + + // Check the migration of textfield fields and well as basic settings. + $field_name = strtolower(str_replace('-', '_', $old_fields['textfield']['name'])); + $field = field_info_field($field_name); + $this->assertNotNull($field, t('The user field has been created.')); + $this->assertEqual($field['type'], 'text', t('Textfields are mapped to fields of type text.')); + + $instance = field_info_instance($field_name, 'user'); + $this->assertNotNull($instance, t('The field has an instance attached to users.')); + $this->assertEqual($old_fields['textfield']['title'], $instance['label'], t('Field label is preserved.')); + $this->assertEqual($old_fields['textfield']['explanation'], $instance['description'], t('Field description is preserved.')); + $this->assertTrue($instance['required'], t('Required fields are preserved.')); + $this->assertEqual($old_fields['textfield']['weight'], $instance['widget']['weight'], t('Weight gets preserved for widgets.')); + $this->assertEqual($old_fields['textfield']['weight'], $instance['display']['full']['weight'], t('Weight gets preserved when displaying fields.')); + $this->assertEqual($old_fields['textfield']['value'], $profile_user->{$field_name}[FIELD_LANGUAGE_NONE][0]['value'], t('Textfield values are migrated.')); + + // Check the migration of textarea fields. + $field_name = strtolower(str_replace('-', '_', $old_fields['textarea']['name'])); + $field = field_info_field($field_name); + $this->assertNotNull($field, t('The user field has been created.')); + $this->assertEqual($field['type'], 'text_long', t('Textareas are mapped to fields of type text_long.')); + + $instance = field_info_instance($field_name, 'user'); + $this->assertFalse($instance['required'], t('Not required fields are preserved.')); + $this->assertEqual($old_fields['textarea']['value'], $profile_user->{$field_name}[FIELD_LANGUAGE_NONE][0]['value'], t('Textarea values are migrated.')); + + // Check the migration of checkbox fields. + $field_name = strtolower(str_replace('-', '_', $old_fields['checkbox']['name'])); + $field = field_info_field($field_name); + $this->assertNotNull($field, t('The user field has been created.')); + $this->assertEqual($field['type'], 'list_boolean', t('Checkboxes are mapped to fields of type list_boolean.')); + $this->assertEqual($old_fields['checkbox']['value'], $profile_user->{$field_name}[FIELD_LANGUAGE_NONE][0]['value'], t('Checkbox values are migrated.')); + } + + // This is an exact copy of the profile_schema. + function profileSchema() { + $schema['profile_field'] = array( + 'description' => 'Stores profile field information.', + 'fields' => array( + 'fid' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Primary Key: Unique profile field ID.', + ), + 'title' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Title of the field shown to the end user.', + ), + 'name' => array( + 'type' => 'varchar', + 'length' => 128, + 'not null' => TRUE, + 'default' => '', + 'description' => 'Internal name of the field used in the form HTML and URLs.', + ), + 'explanation' => array( + 'type' => 'text', + 'not null' => FALSE, + 'description' => 'Explanation of the field to end users.', + ), + 'category' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => 'Profile category that the field will be grouped under.', + ), + 'page' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'description' => "Title of page used for browsing by the field's value", + ), + 'type' => array( + 'type' => 'varchar', + 'length' => 128, + 'not null' => FALSE, + 'description' => 'Type of form field.', + ), + 'weight' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'size' => 'tiny', + 'description' => 'Weight of field in relation to other profile fields.', + ), + 'required' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'size' => 'tiny', + 'description' => 'Whether the user is required to enter a value. (0 = no, 1 = yes)', + ), + 'register' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'size' => 'tiny', + 'description' => 'Whether the field is visible in the user registration form. (1 = yes, 0 = no)', + ), + 'visibility' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'size' => 'tiny', + 'description' => 'The level of visibility for the field. (0 = hidden, 1 = private, 2 = public on profile but not member list pages, 3 = public on profile and list pages)', + ), + 'autocomplete' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'size' => 'tiny', + 'description' => 'Whether form auto-completion is enabled. (0 = disabled, 1 = enabled)', + ), + 'options' => array( + 'type' => 'text', + 'not null' => FALSE, + 'description' => 'List of options to be used in a list selection field.', + ), + ), + 'indexes' => array( + 'category' => array('category'), + ), + 'unique keys' => array( + 'name' => array('name'), + ), + 'primary key' => array('fid'), + ); + + $schema['profile_value'] = array( + 'description' => 'Stores values for profile fields.', + 'fields' => array( + 'fid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + 'description' => 'The {profile_field}.fid of the field.', + ), + 'uid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + 'description' => 'The {users}.uid of the profile user.', + ), + 'value' => array( + 'type' => 'text', + 'not null' => FALSE, + 'description' => 'The value for the field.', + ), + ), + 'primary key' => array('uid', 'fid'), + 'indexes' => array( + 'fid' => array('fid'), + ), + 'foreign keys' => array( + 'fid' => array('profile_field' => 'fid'), + 'uid' => array('users' => 'uid'), + ), + ); + + return $schema; + } +}