Index: database/database.mysql =================================================================== RCS file: /cvs/drupal/drupal/database/database.mysql,v retrieving revision 1.174 diff -U3 -r1.174 database.mysql --- database/database.mysql 23 Mar 2005 20:36:41 -0000 1.174 +++ database/database.mysql 24 Mar 2005 18:31:02 -0000 @@ -444,10 +444,11 @@ category varchar(255) default NULL, page varchar(255) default NULL, type varchar(128) default NULL, - weight tinyint(1) DEFAULT '0' NOT NULL, - required tinyint(1) DEFAULT '0' NOT NULL, - register tinyint(1) DEFAULT '0' NOT NULL, - visibility tinyint(1) DEFAULT '0' NOT NULL, + weight tinyint(1) default '0' NOT NULL, + multiple tinyint(1) default '0' NOT NULL, + required tinyint(1) default '0' NOT NULL, + register tinyint(1) default '0' NOT NULL, + visibility tinyint(1) default '0' NOT NULL, options text, KEY category (category), UNIQUE KEY name (name), Index: database/database.pgsql =================================================================== RCS file: /cvs/drupal/drupal/database/database.pgsql,v retrieving revision 1.109 diff -U3 -r1.109 database.pgsql --- database/database.pgsql 23 Mar 2005 20:36:41 -0000 1.109 +++ database/database.pgsql 24 Mar 2005 18:31:02 -0000 @@ -462,10 +462,11 @@ category varchar(255) default NULL, page varchar(255) default NULL, type varchar(128) default NULL, - weight smallint DEFAULT '0' NOT NULL, - required smallint DEFAULT '0' NOT NULL, - register smallint DEFAULT '0' NOT NULL, - visibility smallint DEFAULT '0' NOT NULL, + weight smallint default '0' NOT NULL, + multiple smallint default '0' NOT NULL, + required smallint default '0' NOT NULL, + register smallint default '0' NOT NULL, + visibility smallint default '0' NOT NULL, options text, UNIQUE (name), PRIMARY KEY (fid) Index: database/updates.inc =================================================================== RCS file: /cvs/drupal/drupal/database/updates.inc,v retrieving revision 1.100 diff -U3 -r1.100 updates.inc --- database/updates.inc 23 Mar 2005 06:12:30 -0000 1.100 +++ database/updates.inc 24 Mar 2005 18:31:03 -0000 @@ -104,7 +104,8 @@ "2005-02-23" => "update_125", "2005-03-03" => "update_126", "2005-03-18" => "update_127", - "2005-03-21" => "update_128" + "2005-03-21" => "update_128", + "2005-03-23" => "update_129" ); function update_32() { @@ -2350,4 +2351,16 @@ return $ret; } +function update_129() { + $ret = array(); + + if ($GLOBALS['db_type'] == 'mysql') { + $ret[] = update_sql('ALTER TABLE {profile_fields} ADD multiple tinyint(1) default 0 NOT NULL'); + } + elseif ($GLOBALS['db_type'] == 'pgsql') { + $ret[] = update_sql('ALTER TABLE {profile_fields} ADD multiple smallint default 0 NOT NULL'); + } + + return $ret; +} ?> Index: modules/profile.module =================================================================== RCS file: /cvs/drupal/drupal/modules/profile.module,v retrieving revision 1.88 diff -U3 -r1.88 profile.module --- modules/profile.module 18 Mar 2005 07:07:04 -0000 1.88 +++ modules/profile.module 24 Mar 2005 18:31:03 -0000 @@ -144,20 +144,31 @@ } function profile_load_profile(&$user) { - $result = db_query('SELECT f.name, f.type, v.value FROM {profile_fields} f INNER JOIN {profile_values} v ON f.fid = v.fid WHERE uid = %d', $user->uid); + $multiple_values = array(); + $result = db_query('SELECT f.name, f.type, f.multiple, v.value FROM {profile_fields} f INNER JOIN {profile_values} v ON f.fid = v.fid WHERE uid = %d', $user->uid); while ($field = db_fetch_object($result)) { - if (empty($user->{$field->name})) { + if ($field->multiple && $field->value) { + $multiple_values[$field->name][] = $field->value; + } + elseif (empty($user->{$field->name})) { $user->{$field->name} = _profile_field_serialize($field->type) ? unserialize($field->value) : $field->value; } } + + // Add fields with multiple values. + foreach ($multiple_values as $name => $values) { + if (empty($user->{$name}) && $values) { + $user->{$name} = $values; + } + } } function profile_save_profile(&$edit, &$user, $category) { if (($_GET['q'] == 'user/register') ? 1 : 0) { - $result = db_query('SELECT fid, name, type FROM {profile_fields} WHERE register = 1 ORDER BY category, weight'); + $result = db_query('SELECT fid, name, type, multiple FROM {profile_fields} WHERE register = 1 ORDER BY category, weight'); } else { - $result = db_query("SELECT fid, name, type FROM {profile_fields} WHERE LOWER(category) = LOWER('%s')", $category); + $result = db_query("SELECT fid, name, type, multiple FROM {profile_fields} WHERE LOWER(category) = LOWER('%s')", $category); // We use LOWER('%s') instead of PHP's strtolower() to avoid UTF-8 conversion issues. } while ($field = db_fetch_object($result)) { @@ -165,7 +176,15 @@ $edit[$field->name] = serialize($edit[$field->name]); } db_query("DELETE FROM {profile_values} WHERE fid = %d AND uid = %d", $field->fid, $user->uid); - db_query("INSERT INTO {profile_values} (fid, uid, value) VALUES (%d, %d, '%s')", $field->fid, $user->uid, $edit[$field->name]); + // Flatten out multiple selects. + if (is_array($edit[$field->name]) && $field->multiple) { + foreach ($edit[$field->name] as $key => $value) { + db_query("INSERT INTO {profile_values} (fid, uid, value) VALUES (%d, %d, '%s')", $field->fid, $user->uid, $value); + } + } + else { + db_query("INSERT INTO {profile_values} (fid, uid, value) VALUES (%d, %d, '%s')", $field->fid, $user->uid, $edit[$field->name]); + } // Mark field as handled (prevents saving to user->data). $edit[$field->name] = null; } @@ -182,7 +201,15 @@ case 'textarea': return check_output($value); case 'selection': - return $browse ? l(drupal_specialchars($value), "profile/$field->name/". check_url($value)) : drupal_specialchars($value); + if (is_array($value)) { + foreach($value as $v) { + $values[] = $browse ? l(drupal_specialchars($v), "profile/$field->name/". check_url($v)) : drupal_specialchars($v); + } + return implode(', ', $values); + } + else { + return $browse ? l(drupal_specialchars($value), "profile/$field->name/". check_url($value)) : drupal_specialchars($value); + } case 'checkbox': return $browse ? l(strip_tags($field->title), "profile/$field->name") : drupal_specialchars($field->title); case 'url': @@ -276,7 +303,7 @@ $fields[$category] .= form_checkbox($field->title, $field->name, 1, $edit[$field->name], _profile_form_explanation($field), NULL, $field->required); break; case 'selection': - $options = array('--'); + $options[-1] = '--'; $lines = split("[,\n\r]", $field->options); foreach ($lines as $line) { if ($line = trim($line)) { @@ -284,7 +311,7 @@ } } - $fields[$category] .= form_select($field->title, $field->name, $edit[$field->name], $options, _profile_form_explanation($field), 0, 0, $field->required); + $fields[$category] .= form_select($field->title, $field->name, $edit[$field->name], $options, _profile_form_explanation($field), 0, $field->multiple, $field->required); break; case 'date': $fields[$category] .= _profile_date_field($field, $edit); @@ -448,7 +475,7 @@ } if (!form_get_errors()) { - db_query("INSERT INTO {profile_fields} (title, name, explanation, category, type, weight, required, register, visibility, options, page) VALUES ('%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, '%s', '%s')", $data['title'], $data['name'], $data['explanation'], $data['category'], $type, $data['weight'], $data['required'], $data['register'], $data['visibility'], $data['options'], $data['page']); + db_query("INSERT INTO {profile_fields} (title, name, explanation, category, type, weight, multiple, required, register, visibility, options, page) VALUES ('%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, %d, '%s', '%s')", $data['title'], $data['name'], $data['explanation'], $data['category'], $type, $data['weight'], $data['multiple'], $data['required'], $data['register'], $data['visibility'], $data['options'], $data['page']); cache_clear_all(); @@ -476,7 +503,7 @@ profile_validate_form($data); if (!form_get_errors()) { - db_query("UPDATE {profile_fields} SET title = '%s', name = '%s', explanation = '%s', category = '%s', weight = %d, required = %d, register = %d, visibility = %d, options = '%s', page = '%s' WHERE fid = %d", $data['title'], $data['name'], $data['explanation'], $data['category'], $data['weight'], $data['required'], $data['register'], $data['visibility'], $data['options'], $data['page'], $fid); + db_query("UPDATE {profile_fields} SET title = '%s', name = '%s', explanation = '%s', category = '%s', weight = %d, multiple = %d, required = %d, register = %d, visibility = %d, options = '%s', page = '%s' WHERE fid = %d", $data['title'], $data['name'], $data['explanation'], $data['category'], $data['weight'], $data['multiple'], $data['required'], $data['register'], $data['visibility'], $data['options'], $data['page'], $fid); cache_clear_all(); @@ -513,6 +540,7 @@ $group .= form_textarea(t('Explanation'), 'explanation', $edit['explanation'], 70, 3, t('An optional explanation to go with the new field. The explanation will be shown to the user.')); if ($type == 'selection') { $group .= form_textarea(t('Selection options'), 'options', $edit['options'], 70, 8, t('A list of all options. Put each option on a separate line. Example options are "red", "blue", "green", etc.')); + $group .= form_checkbox(t('Multiple select'), 'multiple', 1, $edit['multiple'], t('Allows users to select more than one item in this field.')); } $group .= form_weight(t('Weight'), 'weight', $edit['weight'], 5, t('The weights define the order in which the form fields are shown. Lighter fields "float up" towards the top of the category.')); $group .= form_radios(t('Visibility'), 'visibility', $edit['visibility'], array(PROFILE_PRIVATE => t('Private field, content only available to privileged users.'), PROFILE_PUBLIC => t('Public field, content shown on profile page but not used on member list pages.'), PROFILE_PUBLIC_LISTINGS => t('Public field, content shown on profile page and on member list pages.')));