Add severity/type behaviour, like watchdog() function, to drupal_set_message() for theming purposes.
greg.harvey - September 29, 2008 - 09:43
| Project: | Drupal |
| Version: | 7.x-dev |
| Component: | base system |
| Category: | feature request |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | needs work |
Description
It would be cool to have...
... something like a form_set_message() function, which has a form-id or a form element parameter, where you could tell which form initiated the message. And then you could call a drupal_set_message() with a form-id or something..
See http://drupal.org/node/305570#comment-1033941 for original request.

#1
Allow me to expand on this. I have, three times in the last year, been asked if user messages can appear in a different place on the page to all other messages. And the answer, broadly, is "no!" - because the only way to achieve this that I can think of would be to hack user.module so all user messages have a type of 'user' and then read the message string to decide whether to render that message as an error, a warning or just a status message.
Which sucks! =(
However, the drupal_set_message() and drupal_get_messages() functions could be expanded upon to allow this to work. I have decided to supply a patch. This is untested, as I'm doing it very quickly to demonstrate what I mean, but I think the patch code will explain better than words what I'm driving at and how useful this could be. And who knows, it might just work!
PLEASE DISREGARD THE REST OF THIS THREAD UNTIL HERE.
Posts 1 through 7 are part of a previous discussion.
Patches in this post are deliberately de-listed. Replacement patch is HERE.
I have also provided a patch for form_set_error() showing it using the proposed new functionality. Clearly theme_status_messages() in theme.inc would need refactoring too, but I can't find any other instances where this would potentially create a problem.
With the attached patch applied, it is the intention that any of the following possibilities could, if set, exist in the
$messagesarray saved in the session - I have done this in the form of drupal_set_message() code the module executed followed by the result in the$messagesarray:<?php
// these are the parameters available with the attached drupal_set_message function, for reference
function drupal_set_message($message = NULL, $type = 'status', $module = NULL, $mid = NULL, $repeat = TRUE) {
...
}
// this is how things are now
drupal_set_message(t('A message.'));
drupal_set_message(t('Another message.'));
$messages['status'] = array(
'A message.',
'Another message.',
)
drupal_set_message(t('An error.'), 'error');
drupal_set_message(t('Another error.'), 'error');
$messages['error'] = array(
'An error.',
'Another error.',
)
drupal_set_message(t('Custom message.'), 'some_other_type');
$messages['some_other_type'] = array(
'Custom message.',
)
// this is an example where form_set_error() might have sent the form ID of the login form as the message ID
// you still have the type, but you also have the form ID so you can get these specific messages with drupal_get_messages()
drupal_set_message(t('Your passwords do not match.'), 'error', NULL, 'user_login');
drupal_set_message(t('You must provide a valid postcode.'), 'error', NULL, 'user_login');
$messages['error']['user_login'] = array(
'Your passwords do not match.',
'You must provide a valid postcode.',
)
// and this is an example of user.module grouping its errors together
drupal_set_message(t('Your passwords do not match.'), 'error', 'user');
drupal_set_message(t('You must provide a valid postcode.'), 'error', 'user');
$messages['error']['user'] = array(
'Your passwords do not match.',
'You must provide a valid postcode.',
);
?>
I've created a context variable for drupal_get_messages() so it knows how to handle type, which is set to 'normal' by default so if developers ignore the new options I've attempted to make it so they are totally unaffected - the function falls back to the original Drupal 6.x behaviour. These extras should behave as additional options and not interfere with current messaging functionality at all. That is my intention anyway.
To illustrate how this might be useful, I return to my original use case at the start of this comment. With this new functionality, the user module could set all messages like this:
<?php
drupal_set_message(t('An error set in the user module.'), 'error', 'user');
// or from a form validate function
form_set_error('some_field', t('You made a mistake in this field.'), FALSE, 'user');
?>
As a theme developer, I can now override the core theme function for status messages so it excludes the user module messages, which might look something like this in template.php:
<?phpfunction phptemplate_status_messages($display = NULL) {
$output = '';
// I've told drupal_get_messages to expect an array of modules instead of the standard behaviour
foreach (drupal_get_messages($display, TRUE, 'modules') as $type => $messages) {
$output .= "<div class=\"messages $type\">\n";
if (count($messages) > 1) {
$output .= " <ul>\n";
foreach ($messages as $message) {
$output .= ' <li>' . $message . "</li>\n";
}
$output .= " </ul>\n";
}
else {
$output .= $messages[0];
}
$output .= "</div>\n";
}
return $output;
}
?>
Now that drupal_get_messages() is expecting to receive an array of module names in $type, I can call the theme function like this and it will return messages from all modules *except* for user.module:
<?php$modules = module_list();
unset($modules['user']);
print theme('status_messages', $modules);
?>
And I can call it again to give me the user.module messages separately, in a different part of the page:
<?php$modules = array('user' => 'user');
print theme('status_messages', $modules);
?>
Or I could (and would, if I were doing things properly of course) do this in preprocess functions so the two different message outputs were available as variables in templates. =)
#2
Changing status... await feedback with interest. =)
#3
we just discussed in #305570: Set a new message type why a module name as parameter is a bad idea.
as I see I still not convinced you..
#4
To my mind we discussed why you can't do it in the current system. That discussion was very useful, but I didn't see any rationale in your posts to indicate it was a bad idea in general. I totally accept your point that module name as THE ONLY parameter is a bad idea, which is why this patch offers both by module and by type options simultaneously - a message can be of TYPE 'error' and belong to MODULE 'user' because of the new (optional) messages array construction of
array(type => array(module => message) ). Take a look at the patch and examples and you'll see it's totally different to what was initially proposed.Perhaps you can explain in more detail why you think by module message categorisation, as an ADDITIONAL option, is something you don't like?? I can't imagine why it would offend you as it avoids the issues you rightly raised. :-/
#5
you want all messages which are somehow connected to the user module to be displayed in the specific part of your web page, right?
so, there is a custom module, which hooks into the user_login form and into some other forms of another modules.
how should be the messages of this module categorized? if it is not categorized as "user" then the message will not be on the place where you want it. If the messages are categorized as the custom module name, then you could put the messages of this custom module into the same place as "user" messages. But there are some messages in the module which are not "user" messages..
then you could tell to categorize messages by core modules.. what if the message is not connected to any core module, and what if 1 message is connected to two core modules?
this is not a solution for anything, this is pure chaos..
#6
Hmm, I think you're worrying about this way too much. You can't stop developers doing silly things. If that were a major concern, hook_nodeapi would not exist for a start! There's all sorts of chaos people can cause with that. Just because something *might* be badly implemented is not a reason not to include it. But anyway... I don't think the crucial points are getting through here.
1. NOTHING CHANGES.
2. NOTHING CHANGES.
3. NOTHING CHANGES. ;-)
4. NOTHING will fall outside of the current options:
- status
- error
- warning
See? NOTHING CHANGED.
5. ADDITIONALLY, if a module developer wants to (and I'm getting the feeling you won't ... ;-) then s/he can assign the message to their module. Perhaps you can make that automatic, e.g. module developers cannot over-ride it (though I think that's too rigid).
6. Finally, as you suggested, the message can also carry an ID telling you where it came from. Again, this could be enforced, not an option developers can change (though, again, I think that's too rigid).
So let's work through an example, assuming I've changed this patch as described above:
- $type: still set by the developer and can be either 'status', 'warning' or 'error'
- $module: set automatically, the name of the module where the drupal_set_message() function is called
- $mid: the ID of the message, set automatically in form_set_error() to the $form_id of that form, optionally set elsewhere
So, effectively, the format of drupal_set_message might not change from a developer's perspective:
<?phpdrupal_set_message('this is the message', 'status');
?>
But the resulting $messages array looks like this:
Array (status => Array (
module_name => Array (
0 => 'this is the message'
)
)
)
Where module_name is dynamically generated by Drupal and status is one of the three current options. I see no chaos there...?
#7
I'm doing a sanity check on this - emailed the following to all the London Drupal developers I know to see what comes back. I'd like to get a range of opinions from the wider community:
#8
Ok, so I'm insane. LOL.
Well, sort of. Actually I explained myself badly and the email chatter has helped me to clarify what I want further.
The example here is the watchdog() function. It has a $type parameter for carrying a sort of categorisation and it has a $severity parameter for the actual nature of the message. This is all I want to see in drupal_set_message(). I thought the default value for $type might be module name, hence calling it module, but the general consensus is that this is a dumb idea, so I stand corrected. ;-)
So, copying the watchdog() example, I would like to provide a patch to make drupal_set_message() work like this:
<?php// these are the parameters available with the attached drupal_set_message function, for reference
function drupal_set_message($message = NULL, $severity = 'status', $repeat = TRUE, $type = NULL) {
...
}
?>
This would bring it in to line with watchdog(), which makes perfect sense, no?
#9
With the last post in mind, here is a much more simple patch.
#10
And a change of title to better describe what's happening here.
#11
The last submitted patch failed testing.
#12
New patch - I re-worked this and tested it properly. Hopefully it will pass this time.
#13
The last submitted patch failed testing.
#14
Odd failure message. =/
Re-test please!
#15
The last submitted patch failed testing.