0

I'm using the Message module to notify users when someone commented on one of their nodes. I'd like to extend this mechanism and also let users know when they're mentioned (e.g. @user) in a comment.

I tried setting up the following Rule:

  • Event: After saving a new comment.
  • Condition: Text comparison: comment contains @.
  • Action: Create a new entity: message.

I should now determine whether the text after @ is a user and, if so, store it to use it in the action. The problem is that I don't know how to do that. Another tricky constatation is that the username can contain spaces. After asking How to prevent users from being registered when their username contains a space?, I've made sure that usernames never contain spaces.

Is it possible to solve my problem by working on with Rules or is there another solution (coding, I suppose)?

1

You can do it this way:

  1. Copy the function function mentions_get_mentions($text) from mention module repo, It's defined on line 359.
  2. Unfortunately I can't say if the regex from mention module actually works for user's with space in their name, and the function doc comment is not helpful either. So you could use your own regex

What kind of regex?

#\s?@([a-zA-Z0-9 ])+(?|[^a-zA-Z0-9 ]|$)#


How did I do it?

#                  : Identifies beginning of the RegEx pattern.
(?|^|[^a-zA-Z0-9]) : match any non-username chars or beginning of subject string.
@  : A plain @ char is needed.
([a-zA-Z0-9 ])+    : match any username char after a "@" including whitespace.
(?|$|[^a-zA-Z0-9]) : match any non-username chars or ending of subject string.
#                  : Identifies ending of the RegEx pattern.

Now all you have to do is to write a custom rule, pass it a text variable, and get list of user entities (or uid's) back. You could make sure users who matched through regex actually exists in database too.

A few more notes

  • A ? in regex causes the group NOT to appear in matched groups. Useful when you need to define a group but don't need it in the array of matched strings.
  • ^|[^a-zA-Z0-9] means beginning of subject string or (the | is or) any char which is NOT (said by ^ in []) in ranges a-z, A-Z and 0-9.

Does this regex have bugs? yes

  • The returned user name(s) from regex can have an space at the end of their name, you could trim each name. It will be easier than to fix it in the regex pattern IMO.
  • It displays a funny character in my shell when matching an string with unicode characters in them. preg_match supports such multi-byte characters though, and the u flag dis not work.

But again first check the function from mentions.

References:

Mentions module
PHP preg_match doc
Writing custom rules for drupal, Rules DEV doc
Writing custom rules, A blog tutorial

one more thing I couldn't find in google right now: there is a module for rules which provides text tools, I think it had regex matching and you wont need a custom module.

What is this "Regex" you're talking about all the time anyway?

RegEx stands for Regular Expression. It's a search pattern and is extremely very powerfull. While itself can be complicated (sometimes), many task which usually take a lot of time and effort to be done, such as parsing a text, can be done using regex in one line!
In this case we are looking for usernames in a paragraph in order to turn them into links. First we describe what a username looks like (the text patterns of username): any part of text which begins with letter, followed by a sequence of more letters and numbers.
Then we write it as a RegEx (What I've done here) and later extract usernames by passing both text and RegEx pattern to preg_match function and taking usernames array back (the function is preg_match).
If I want to talk about all the benefits it wont fit in here, so I suggest you a little search on duckduckgo. It's a handy tool to have, a powerful one try to learn it :)

  • I've updated my question and banned out the problem of spaces in usernames. I've also taken a short look at the code from the Mention module, but I still don't understand how and where you're using it. Are you trying to create a custom module? If so, how are you going to create the Message? Please provide some more information in your answer. – Jeroen Aug 3 '14 at 17:12
  • @Jeroen are you OK with writing a custom module? what I had in mind was adding the functionality to drupal.org/project/rules_data_transforms , you should write a custom rule action (in a module, the mentioned module IMO is best place instead of a new custom module), which takes two parameter: a text, a RegEx pattern, and returns all matched patterns in text.so you give it your comment's text and the specified RegEx and get back all usernames, you can further load user entities by name using rule action 'load entity by property'... – hkoosha Aug 5 '14 at 8:56
  • @Jeroen I think this is a useful thing (pattern matching for rules). You can start a new sandbox project on Drupal.org , or even better on github and I'll help you get it done. I can't do it myself right now I'm too bussy, but it's an easy one. One last thing: before beginning this module, you should ask on Drupal's IRC on freenode if such a module already exists or not? – hkoosha Aug 5 '14 at 8:58
1

First, let me remind you that this solution will only work when usernames don't contain spaces. Our main goal is to get an array of the uid's of the users that were mentioned in a comment and then use this array to notify the users with a Message. In my code, one can mention a user by using @user, but the @-sign can be replaced by every desired character.

  1. Write a function MYMODULE_users_in_comment($text, $array) that returns an array with all the words after a @-sign. Useful links to do this are:

  2. Write a function MYMODULE_uid_users_in_comment($text) that replaces every valid username in the output of the previous function with that user's uid. Use user_load_by_name() for this and read Delete an element from an array to delete invalid 'usernames'.

  3. Implement MYMODULE_comment_insert() and MYMODULE_comment_update(): loop over the elements of MYMODULE_uid_users_in_comment($comment) in order to create a Message for every user. You can find more information about how to create Messages programmatically here and in the message_example.module file of the Message module.

Of course, in the final step, you can use the array of uid's for other notifying tools as well (e.g. email).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.