Desire ability to control profile fields by the user's role
| Project: | Drupal |
| Version: | 4.7.2 |
| Component: | profile.module |
| Category: | feature request |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | closed |
It seems rather obvious to me there is a general need for profile fields to be controlled by the users role. I have a specific instance where this is true, but believe it is a general need.
In my case I'm building a site for a community of people trained in a certain practice. I want those trained in that practice to have extra fields in their profile which allow them to describe themselves in terms of that practice. These people are expected to be professionals in this area, and I want their profile to reflect those professional credentials.
FWIW, I've looked at both the bio and usernodes modules since they provide similar functionality. However in both cases the information is not mingled into the user profile, but displayed separately. I think this bio information belongs in the user profile.
I looked carefully at this in both 4.6 and 4.7 (I originally wrote this patch last fall) and concluded it required a change to the profile.module.
Let me describe the required changes. I've glanced at the CVS HEAD and it appears the same changes will work there. But there are enough differences between 4.7.2 and CVS HEAD that I am giving the instructions relative to 4.7.2. Attached to this is the profile.module I am currently using on my 4.7.2 system.
The first change is in the database table profile_fields, to add a field named 'roles' which I sized as varchar(255). It can probably be smaller.
The first code change is to add the following in profile_field_form:
$all_roles = user_roles();
unset($all_roles[DRUPAL_ANONYMOUS_RID]);
$form['fields']['roles'] = array(
'#type' => 'checkboxes',
'#title' => t('Roles'),
'#options' => $all_roles,
'#default_value' => isset($edit['roles']) ? unserialize($edit['roles']) : "",
'#description' => t('Select the roles this for which profile field should be available.')
);I put it just below the $form['fields']['visibility']. This adds a set of checkboxes to the form that edits a field letting the admin select which roles the field is valid for. I remove the anonymous user role because this isn't appropriate for that role.
In profile_field_form_submit there are two db_query calls to update the table. In the first I added 'roles' to the end of the list of fields to set, and then at the end of the list of arguments I added: serialize($form_values['roles']) ... in the second I added "roles = '%s'" in the SQL and in the matching place in the argument list I added: serialize($form_values['roles'])
That change ensures the data from the form gets saved into the database.
In profile_browse there are two places with a comment reading "Compile a list of fields to show." and immediately following is a db_query to SELECT from profile_fields. Add to the list of fields retrieved "roles". This ensures the roles data is retrieved.
In profile_load_profile, in the db_query to SELECT from profile_fields, add f.roles to the list of fields. Then there is an "if" closely following which must be changed to read:
if (_profile_user_can_have_field($field, $user) && empty($user->{$field->name})) {In profile_save_profile there are two SELECT statements from profile_fields. Again add "roles" to the list of fields. There is a while loop closely following, and insert the following at the top of that loop:
if (!_profile_user_can_have_field($field, $user)) {
continue;
}This makes sure that only the fields the user is allowed to have are saved.
In profile_view_field there is an "if" near the beginning which should be changed to this:
if (_profile_user_can_have_field($field, $user) && $value = $user->{$field->name}) {This ensures that even if the code gets into profile_view_field, only if the user is allowed to have that field will it be displayed.
In profile_view_profile there is a loop over the fields which calls profile_view_field. I added the following to the head of that loop:
if (!_profile_user_can_have_field($field, $user)) {
continue;
}In profile_form_profile there is a similar loop and I added similar code to the head of that loop:
if (!_profile_user_can_have_field($field, $user)) {
continue;
}Finally, there is the definition of _profile_user_can_have_field .. it's purpose is to check whether the given $user has the correct role to have the given field.
function _profile_user_can_have_field($field, $user) {
// Flag to detect whether one of the roles are set for this field
$hadnonzero = FALSE;
if (isset($field->roles) && $field->roles != "") {
$field_roles = unserialize($field->roles);
if (is_array($field_roles)) {
unset($field_roles[DRUPAL_ANONYMOUS_RID]);
foreach ($field_roles as $rolenum => $roleval) {
if ($roleval != 0) {
if (isset($user->roles[$rolenum])) {
// If the role is set for this field, and this user has this role,
// then they are allowed to have this field
return TRUE;
}
// We're looking at a role that is set for this field
// So set the flag
$hadnonzero = TRUE;
}
}
}
}
if ($hadnonzero == FALSE) {
// If no roles were set for this field, then this means that the field
// is open for everybody to use.
return TRUE;
}
// Otherwise the role was set for this field, but the user did not have
// the role. So they are not allowed the field.
return FALSE;
}| Attachment | Size |
|---|---|
| profile_9.module | 33.42 KB |

#1
I should note that the file version numbers in the $Id$ are relative to my private CVS. However I've only made changes for this feature.
Attached to this note is a diff -u for my changes.
#2
In my description I see I left out describing the profile_field_form_submit changes. They are straightforward, to add matching bits to the SQL statements, and to the argument list.
However I found just now a bug in the patch I submitted. In the INSERT INTO you need to add another "'%s'" at the end of the list of spots the values are inserted into.
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')", $form_values['title'], $form_values['name'], $form_values['explanation'], $form_values['category'], $form_values['type'], $form_values['weight'], $form_values['required'], $form_values['register'], $form_values['visibility'], $form_values['options'], $form_values['page'], serialize($form_values['roles']));#3
This would be a very nice feature.
Anyway, there is so much going on in HEAD about user profiles that it would be interesting to have some feedback about this one.
#4
Yeah, I know the preference is for a submitted patch to be against HEAD. But in this case since I'm not involving myself with HEAD activity, I didn't want to try and track that down.
I was pondering my approach recently ... and I'm now wondering whether it would be better to use the normal access control page to configure which profile fields are applicable to which roles.
In the method posted on this RFE, it controls that access via a field edited on the profile field page. Essentially that's a set of permissions handled outside the normal access control. Is there an architectural principle being violated? In other words, are we supposed to configure all permissions through the access control page? I don't know, which is why I'm asking the question.
If this were presented on the normal access control page ... you would have one row on that page for each profile field. You would click for each role the profile field applies to. You would lose the ability for a profile field to automatically apply to all roles if you don't select any applicable roles.
#5
At this time we have two ways to configure access permissions: using the access control page (for site-wide permissions) and a very simple node access control (that is included in core, but needs 3rd party modules to user interaction).
I do not think that having another place to set permissions would be bad, but it wouldn't be good also.
In my opinion, and except for nodes, I think that everything about permissions should be set in "access control" page. But I also think that this is one of the pages that need a complete usability refactoring.
#6
Just adding myself to follow up this thread.
#7
So to install the above do I just copy the code from profile_9.module and use it to replace all of the original code in the profile.module file? I tried this including the little '%s' fix. It didn't crash my system (4.7), I'm able to see the roles one each profile field form, but when I choose one then press record I get this error :
user warning: Unknown column 'roles' in 'field list' query: UPDATE profile_fields SET title = 'Handicaps', name = 'profile_interne_handicaps', explanation = '', category = 'Bras cassés interne', weight = 0, required = 0, register = 0, visibility = 1, options = 'handicap physique\r\nhandicap mentaux\r\nmaladie mentale\r\nHR', page = '', roles = 'a:4:{i:6;i:6;i:4;i:0;i:2;i:0;i:5;i:0;}' WHERE fid = 66 in C:\wamp\www\includes\database.mysqli.inc on line 121.
What am I doing wrong? I tried updating the PHP. This would be a great feature addition to profiles. Thanks for your work.
John
#8
I said in my original report to add a field "roles" to "profile_fields". Here is the SQL
alter table profile_fields add roles varchar(255);#9
i think that the bio or user profile modules will do what you want at this point. that and any of the profile as a node patches for core would be a better place to continue this.