Another case of Drupal's sensitivity
Steven Jones
If you have a Drupal site with users and you want to allow them to add some profile data about themselves there are a few routes available to you, one of the oldest (and thus simplest) ways is to use profile module. You can add text fields, selects and other bits and bobs to users, with different visibility settings for each field. You also have the chance (in fact it is required that you do) to categorise your fields. These categories then show up as secondary tabs on the user edit page. But what happens when you want to make it really simple and get the profile fields onto the main user edit page itself? At first glance you can't, because if you set the category to 'account', then Drupal will complain. But you can just set the category to 'Account' and you're done, right?
Wrong.
What you've just done is to set yourself up for disaster. The way that a user object is saved and loaded is reasonably clever; You essentially call user_save
passing in the object representing the user and an array of fields to be saved, and the category of those fields. hook_user
is then invoked to let any modules do their stuff and save the right fields to the right places, profile module is one such module, and it will happily look for values in the array of fields passed in to save into its tables.
Spot the problem? Profile module sees 'Account' and 'account' as the same string, which is why the 'hack' described above worked. Lots of other modules will have the following flow to modify a user (you're fine on the /user/X/edit page btw):
- Load a user object.
- Compile an array of changes (add a role, or change username/email.)
- Save the object using
user_save
, passing in those changes.
If no category is given, then 'account' is assumed, profile module will try to save those profile fields that you/I've given categories of 'Account'. But it looks in the array of data passed in for the values to store, and if it can't find a matching field it assumes that the string should be ''. Now it saves those empty strings into the database. Fail.
There are two fixes:
First, don't use any string that is 'account', 'Account' or 'aCcount' etc.
Or, fake the fields on save thus:
Create a new module, with a lower weight that profile module. Implement hook_user like this:
/**
* Implementation of hook_user()
*/
function example_user($op, &$edit, &$account, $category = NULL) {
if (module_exists('profile')) {
switch ($op) {
case 'update':
if (strtolower($category) == 'account') {
$result = _profile_get_fields($category);
while ($field = db_fetch_object($result)) {
if (!isset($edit[$field->name])) {
if (isset($account->{$field->name})) {
$edit[$field->name] = $account->{$field->name};
}
}
}
}
break;
}
}
}
Drupal can be funny about the case of strings you input, so be careful!