I discussed the idea here: http://drupal.org/node/35465
The requirement is that, for my site, my users need to have different sets of profile fields. It seems like such an obvious need that this should be true for any site. In the case of my site, the different user roles have clearly different capabilities and needs. Those MUST show up in as differing profile fields.
The implementation is relatively simple.
In the profile_values table I added a new field named "roles", with type VARCHAR(255).
In the "roles" field the code stores a list of profile names for which the field is valid. It uses preg_match To test whether a given role is in that list. In several places a list of profile fields are generated, and that was modified to test whether that field is visible to the roles the given user has. The other main change was to add checkboxes for all roles to the edit/add role page.
I've attached the modified profile.module. Diff output is below.
*** profile.module.orig Sat Oct 29 18:25:45 2005
--- profile.module Sat Oct 29 18:54:01 2005
***************
*** 76,82 ****
// Compile a list of fields to show
$fields = array();
! $result = db_query('SELECT name, title, type FROM {profile_fields} WHERE fid != %d AND visibility = %d ORDER BY weight', $field->fid, PROFILE_PUBLIC_LISTINGS);
while ($record = db_fetch_object($result)) {
$fields[] = $record;
}
--- 76,82 ----
// Compile a list of fields to show
$fields = array();
! $result = db_query('SELECT name, title, type, roles FROM {profile_fields} WHERE fid != %d AND visibility = %d ORDER BY weight', $field->fid, PROFILE_PUBLIC_LISTINGS);
while ($record = db_fetch_object($result)) {
$fields[] = $record;
}
***************
*** 123,129 ****
else {
// Compile a list of fields to show
$fields = array();
! $result = db_query('SELECT name, title, type FROM {profile_fields} WHERE visibility = %d', PROFILE_PUBLIC_LISTINGS);
while ($record = db_fetch_object($result)) {
$fields[] = $record;
}
--- 123,129 ----
else {
// Compile a list of fields to show
$fields = array();
! $result = db_query('SELECT name, title, type, roles FROM {profile_fields} WHERE visibility = %d', PROFILE_PUBLIC_LISTINGS);
while ($record = db_fetch_object($result)) {
$fields[] = $record;
}
***************
*** 144,152 ****
}
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);
while ($field = db_fetch_object($result)) {
! if (empty($user->{$field->name})) {
$user->{$field->name} = _profile_field_serialize($field->type) ? unserialize($field->value) : $field->value;
}
}
--- 144,152 ----
}
function profile_load_profile(&$user) {
! $result = db_query('SELECT f.name, f.type, v.value, f.roles 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 (_profile_user_can_have_field($field, $user) && empty($user->{$field->name})) {
$user->{$field->name} = _profile_field_serialize($field->type) ? unserialize($field->value) : $field->value;
}
}
***************
*** 154,166 ****
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');
}
else {
! $result = db_query("SELECT fid, name, type 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)) {
if (_profile_field_serialize($field->type)) {
$edit[$field->name] = serialize($edit[$field->name]);
}
--- 154,169 ----
function profile_save_profile(&$edit, &$user, $category) {
if (($_GET['q'] == 'user/register') ? 1 : 0) {
! $result = db_query('SELECT fid, name, type, roles FROM {profile_fields} WHERE register = 1 ORDER BY category, weight');
}
else {
! $result = db_query("SELECT fid, name, type, roles 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)) {
+ if (!_profile_user_can_have_field($field, $user)) {
+ continue;
+ }
if (_profile_field_serialize($field->type)) {
$edit[$field->name] = serialize($edit[$field->name]);
}
***************
*** 175,181 ****
// Only allow browsing of private fields for admins
$browse = user_access('administer users') || $field->visibility != PROFILE_PRIVATE;
! if ($value = $user->{$field->name}) {
switch ($field->type) {
case 'textfield':
return check_plain($value);
--- 178,184 ----
// Only allow browsing of private fields for admins
$browse = user_access('administer users') || $field->visibility != PROFILE_PRIVATE;
! if (_profile_user_can_have_field($field, $user) && $value = $user->{$field->name}) {
switch ($field->type) {
case 'textfield':
return check_plain($value);
***************
*** 260,265 ****
--- 263,271 ----
$fields = array();
while ($field = db_fetch_object($result)) {
+ if (!_profile_user_can_have_field($field, $user)) {
+ continue;
+ }
$category = $field->category;
switch ($field->type) {
case 'textfield':
***************
*** 374,379 ****
--- 380,404 ----
return $edit;
}
+ /**
+ * In the database the profile list is stored as a flat string. We're using
+ * pattern matching to determine whether a role is in the string.
+ *
+ * NOTE: The 'ALL' choice is intended to support (eventually) an ALL checkbox
+ * so that a profile field can automatically show up automatically in all roles.
+ */
+ function _profile_user_can_have_field($field, $user) {
+ if (preg_match('/ALL/', $field->roles)) {
+ return TRUE;
+ }
+ foreach ($user->roles as $rid => $name) {
+ if (preg_match("/$name/", $field->roles)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
function profile_categories() {
$result = db_query("SELECT DISTINCT(category) FROM {profile_fields}");
while ($category = db_fetch_object($result)) {
***************
*** 430,435 ****
--- 455,482 ----
}
/**
+ * The web form for profile_admin_add and profile_admin_edit cause the role
+ * list to arrive as an array. This function turns the array into the
+ * flat string that's stored in the database.
+ *
+ * NOTE: The 'ALL' choice is intended to support (eventually) an ALL checkbox
+ * so that a profile field can automatically show up automatically in all roles.
+ */
+ function _profile_get_roles_from_data($data) {
+ $roles = '';
+ if (array_key_exists('role_ALL', $data)) {
+ $roles = 'ALL';
+ } else if ($data['roles']) {
+ $roles = '';
+ $roles_array = user_roles();
+ foreach ($data['roles'] as $key => $value) {
+ $roles .= ' '.trim($value).' ';
+ }
+ }
+ return $roles;
+ }
+
+ /**
* Menu callback; adds a new field to all user profiles.
*/
function profile_admin_add($type) {
***************
*** 448,454 ****
}
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['vi
sibility'], $data['options'], $data['page']);
cache_clear_all();
--- 495,502 ----
}
if (!form_get_errors()) {
! $roles = _profile_get_roles_from_data($data);
! db_query("INSERT INTO {profile_fields} (title, name, explanation, category, type, weight, required, register, visibility, options, page, roles) VALUES ('%s', '%s', '%s',
'%s', '%s', %d, %d, %d, %d, '%s', '%s', '%s')", $data['title'], $data['name'], $data['explanation'], $data['category'], $type, $data['weight'], $data['required'], $data['register
'], $data['visibility'], $data['options'], $data['page'], $roles);
cache_clear_all();
***************
*** 476,482 ****
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['visibil
ity'], $data['options'], $data['page'], $fid);
cache_clear_all();
--- 524,531 ----
profile_validate_form($data);
if (!form_get_errors()) {
! $roles = _profile_get_roles_from_data($data);
! 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', roles = '%s' WHERE fid = %d", $data['title'], $data['name'], $data['explanation'], $data['category'], $data['weight'], $data['required'], $data['register'],
$data['visibility'], $data['options'], $data['page'], $roles, $fid);
cache_clear_all();
***************
*** 516,521 ****
--- 565,586 ----
}
$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 to
p of the category.'));
$group .= form_radios(t('Visibility'), 'visibility', $edit['visibility'], array(PROFILE_PRIVATE => t('Private field, content only available to privileged users.'), PROFILE_PU
BLIC => 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 memb
er list pages.')));
+
+ $user_roles = user_roles();
+ $roles_selected = is_array($edit['roles']) ? $edit['roles'] : array();
+ foreach ($user_roles as $key => $role) {
+ $the_roles[$role] = $role;
+ if (!is_array($edit['roles'])) {
+ if (preg_match("/$role/", $edit['roles'])) {
+ $roles_selected[$key] = $role;
+ }
+ }
+ }
+ $group .= form_checkboxes(t('Roles'), 'roles',
+ $roles_selected,
+ $the_roles,
+ t('Select the roles this for which profile field should be available.'),
+ NULL, TRUE);
if ($type == 'selection' || $type == 'list') {
$group .= form_textfield(t('Page title'), 'page', $edit['page'], 70, 128, t('The title of the page showing all users with the specified field. The word <code>%value will be substituted with the corresponding value. An example page title is "People whose favorite color is %value". Only applicable if the field is configured to be shown on m
ember list pages.'));
}
| Comment | File | Size | Author |
|---|---|---|---|
| profile_4.module | 24.72 KB | reikiman |
Comments
Comment #1
moshe weitzman commentedpatch at http://drupal.org/node/14149
Comment #2
scarer commentedis there a version of this for 5?
thanks,
sarah
Comment #3
reikiman commentedNo, sorry, I didn't forward port it very far. I noticed looking at 6 code a possibility.. CCK now seems to have an ability to attach CCK fields to user profiles, plus CCK has permissions support so certain fields can require roles (?) to access those fields. I didn't look at the details but it may be possible to put those together to implement the intention I had.
Comment #4
scarer commentedah ok
no worries i'll have a look around
thanks for the prompt response
sarah
Comment #5
1kenthomas commentedhttp://drupal.org/project/cck_field_perms?