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

greg.harvey - September 30, 2008 - 09:34

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 $messages array 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 $messages array:

<?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:

<?php
function 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. =)

Testbed results
form_set_message-form.inc_.patchfailedFailed: Failed to apply patch. Detailed results
drupal_messages-bootstrap.inc_.patchfailedFailed: Failed to apply patch. Detailed results

#2

greg.harvey - September 29, 2008 - 16:38
Status:active» needs review

Changing status... await feedback with interest. =)

#3

Pasqualle - September 29, 2008 - 18:36

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

greg.harvey - September 29, 2008 - 18:54

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

Pasqualle - September 29, 2008 - 19:11

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

greg.harvey - September 29, 2008 - 20:09

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, 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?

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:

<?php
drupal_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

greg.harvey - September 29, 2008 - 20:46

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:

Hi all,

I'm opinion gathering. I put in a feature request and the beginnings of a patch to allow modules to group their messages together using drupal_set_message(). I think this is useful. Let me give you a use case: three times this year I have been asked if the messages from the user module and profile module could appear on one part of the page (effectively the user management messages) and all other messages somewhere else. I can't be the only one regularly fielding such a request? It seems to me IAs and designers are going through a fad of wanting user messages in a "user space" and other messages in a "message space", rather than the Drupal approach which is a message is a message and they all go in the same place, and I can't do this with Drupal right now.

So, I set about re-writing drupal_set_message() and drupal_get_messages() against the Drupal 7.x dev release (badly, probably - I'll let you be the judges of that) and submitted my rough work so far... and got a bit of a mauling. =(

The concept of grouping messages by module name has been described as "chaos", but I don't see it. Take a read, if you have time:
http://drupal.org/node/314756#comment-1035446

I'm after opinions here. Am I on to a good feature, or have I finally gone stark raving bonkers and should drop the whole thing??

Cheers,

G

#8

greg.harvey - September 30, 2008 - 08:56

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

greg.harvey - November 5, 2008 - 17:45

With the last post in mind, here is a much more simple patch.

AttachmentSize
drupal_messages-bootstrap.inc_.patch 4.08 KB
Testbed results
drupal_messages-bootstrap.inc_.patchfailedFailed: 7199 passes, 4 fails, 0 exceptions Detailed results

#10

greg.harvey - September 30, 2008 - 09:26
Title:Ability to get a handle on a specific message generated during validation or submission and theme it.» Add severity/type behaviour, like watchdog() function, to drupal_set_message() for theming purposes.

And a change of title to better describe what's happening here.

#11

Anonymous (not verified) - November 12, 2008 - 07:15
Status:needs review» needs work

The last submitted patch failed testing.

#12

greg.harvey - February 24, 2009 - 14:47
Status:needs work» needs review

New patch - I re-worked this and tested it properly. Hopefully it will pass this time.

AttachmentSize
drupal_set_message.diff 5.88 KB
Testbed results
drupal_set_message.difffailedFailed: 10267 passes, 1 fail, 0 exceptions Detailed results

#13

System Message - February 24, 2009 - 17:25
Status:needs review» needs work

The last submitted patch failed testing.

#14

greg.harvey - February 24, 2009 - 18:15
Status:needs work» needs review

Odd failure message. =/
Re-test please!

AttachmentSize
drupal_set_message.diff 5.87 KB
Testbed results
drupal_set_message.difffailedFailed: 10267 passes, 1 fail, 0 exceptions Detailed results

#15

System Message - February 24, 2009 - 18:30
Status:needs review» needs work

The last submitted patch failed testing.

 
 

Drupal is a registered trademark of Dries Buytaert.