Thanks for overhauling this module. 4.x is a good decision.

It would be very helpful if hook_og was invoked each time a role was added to, or removed from a user. This feature was in the previous version and was quite handy.

I want to modify the og_user_roles_role_add() function and add the following invoke call to the end of the function:
module_invoke_all('og', 'user update', $gid, $uid, $args).
$args would contain the rid that was added, and an action parameter such as $arg['action'] = 'role add'.

I also want to modify the og_user_roles_role_delete() function and add the following invoke call to the end of the function:
module_invoke_all('og', 'user update', $gid, $uid, $args).
$args would contain the rid that was deleted, and an action parameter such as $arg['action'] = 'role delete'.

I am going to start on a patch.

Any thoughts?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

bschilt’s picture

FileSize
2.29 KB

I have created a patch that invokes a hook each time a role is added or deleted from a user in a group. Here is the method signature:

  hook_og_user_roles($op, $gid, $uid, $rid, $args = array())

$op = 'role add' || 'role delete';
$gid = group id
$uid = user id
$rid = role id of the role being added or deleted
$args = empty for now, but can contain custom properties

I added the module_invoke_all() function to the og_user_roles_role_add and og_user_roles_role_delete functions.

function og_user_roles_role_add($gid, $uid, $rid) {
  $granted = db_result(db_query_range("SELECT rid FROM {og_users_roles} WHERE gid = %d AND uid = %d AND rid = %d", $gid, $uid, $rid, 0, 1));
  if (!$granted) {
    db_query("INSERT INTO {og_users_roles} (uid, gid, rid) VALUES (%d, %d, %d)", $uid, $gid, $rid);
    
    module_invoke_all('og_user_roles', 'role add', $gid, $uid, $rid, $args);
  }
}
function og_user_roles_role_delete($gid, $uid, $rid = NULL) {
  if (is_null($rid)) {
    db_query("DELETE FROM {og_users_roles} WHERE gid = %d AND uid = %d", $gid, $uid);
  }
  else {
    db_query("DELETE FROM {og_users_roles} WHERE gid = %d AND uid = %d AND rid = %d", $gid, $uid, $rid);
  }
  
  module_invoke_all('og_user_roles', 'role delete', $gid, $uid, $rid, $args);
}

The biggest change I had to make was in the og_user_roles_page_form_submit handler function. The way this worked previously is that all roles for all users in a group would be deleted, then their roles would be re-added based upon the form's role check box values.

This was an issue since the hook_og_user_roles function was being called for every deletion and addition of roles.

The code I added figures out for each user which roles are going to be added, and which roles are going to be deleted based upon what the user already had saved in the database.

function og_user_roles_page_form_submit($form, &$form_state) {
  $gid = $form['#node']->nid;

  foreach ($form_state['values']['user_roles'] as $uid => $new_roles) {
    //get the user's current roles from the db.
    $original_roles = og_user_roles_get_roles_by_group($gid, $uid); 
    
    //determine which roles to add
    $add_roles = array_diff($new_roles, $original_roles);
    $add_roles = array_filter($add_roles);

    //determine which roles to delete
    $delete_roles = array_diff($original_roles, $new_roles);
    
    foreach ($delete_roles as $rid => $checked) {
      og_user_roles_role_delete($gid, $uid, $rid);
    }

    foreach ($add_roles as $rid => $checked) {
      og_user_roles_role_add($gid, $uid, $rid);
    }
  }

  drupal_set_message(t('The changes have been saved.'));
}

I have successfully tested the new code and it seems to be working great. Please test and let me know of any issues.

Thanks

Brian

bschilt’s picture

FileSize
3.07 KB

I've made a minor change to the previous patch.

I've added the $args = array() parameter to the og_user_roles_role_add and og_user_roles_role_delete signatures. The purpose for this is to allow other modules to pass some custom data to their hook_og_user_roles implementations.

This new patch includes all updates from the previous patch.

function og_user_roles_role_add($gid, $uid, $rid, $args = array()) {
  $granted = db_result(db_query_range("SELECT rid FROM {og_users_roles} WHERE gid = %d AND uid = %d AND rid = %d", $gid, $uid, $rid, 0, 1));
  if (!$granted) {
    db_query("INSERT INTO {og_users_roles} (uid, gid, rid) VALUES (%d, %d, %d)", $uid, $gid, $rid);
    
    module_invoke_all('og_user_roles', 'role add', $gid, $uid, $rid, $args);
  }
}

function og_user_roles_role_delete($gid, $uid, $rid = NULL, $args = array()) {
  if (is_null($rid)) {
    db_query("DELETE FROM {og_users_roles} WHERE gid = %d AND uid = %d", $gid, $uid);
  }
  else {
    db_query("DELETE FROM {og_users_roles} WHERE gid = %d AND uid = %d AND rid = %d", $gid, $uid, $rid);
  }
  
  module_invoke_all('og_user_roles', 'role delete', $gid, $uid, $rid, $args);
}
sun’s picture

Status: Active » Postponed (maintainer needs more info)

ok, we seem to have two issues mixed into one here. The first being an invocation of hook_og(), as the issue title suggests. The second one (perhaps) being a bug fix. The latter I want to see a separate issue for.

For this feature request, I want to hear some more reasoning/use-cases for this hook invocation. If we'll invoke a hook, then we'll invoke hook_og() with a custom $op. And we won't change its function signature.

bschilt’s picture

I have created a separate issue for adjusting how the user roles are added and deleted. You can see that here: http://drupal.org/node/507498

Invoking hook_og() is perfectly fine. When I was invoking the hook, I thought that having a hook_og_user_roles function would be easier for the hook implementations to use if the $rid was a first class parameter, instead of being passed in the $args array. But invoking hook_og() is perfectly suitable too.

Here is why I would like to have a hook called each time a user role is added or deleted. I am using the og_subgroups module to build a hierarchy of groups. One thing that og_subgroups doesn't do is propagate user roles up, down, or sideways along the hierarchy tree. I am working on patching the og_subgroups module so that when a user role is added, that role can be propagated to other groups. Same for when a user role is deleted.

Without having some kind of a hook advertising when a role is added or removed, its not possible to propagate that role. I'm sure there would be other use cases that this would help, but this is why I need to utilize a hook.

I can change the hook signature to be something like:

module_invoke_all('og', 'user role add', $gid, $uid, $args['rid'] = $rid);
module_invoke_all('og', 'user role delete', $gid, $uid, $args['rid'] = $rid);
bschilt’s picture

Here is an updated patch that invokes the hook_og function when a role is added and deleted from a user.

BEFORE INSTALLING THIS PATCH:
This patch is dependent on the patch found here: http://drupal.org/node/507498. Install the change_how_user_roles_are_added_and_deleted.patch before installing this patch.

bschilt’s picture

Status: Postponed (maintainer needs more info) » Needs review
sun’s picture

Title: Add a hook_og call when roles are changed » Invoke hook_og() when roles are changed
Status: Needs review » Postponed

Marking postponed, as this issue depends on #507498: change how user roles are added and deleted.

+++ og_user_roles.module	6 Jul 2009 18:30:02 -0000
@@ -417,16 +417,20 @@ function og_user_roles_get_roles_by_grou
+ * @param $args
+ *   An array containing values set by other modules that are passed to hook_og implementations.
  */
-function og_user_roles_role_add($gid, $uid, $rid) {
+function og_user_roles_role_add($gid, $uid, $rid, $args = array()) {
@@ -434,13 +438,17 @@ function og_user_roles_role_add($gid, $u
+ * @param $args
+ *   An array containing values set by other modules that are passed to hook_og implementations.
  */
-function og_user_roles_role_delete($gid, $uid, $rid = NULL) {
+function og_user_roles_role_delete($gid, $uid, $rid = NULL, $args = array()) {

The PHPDoc description exceeds 80 chars.

However, I also do not understand why this argument has been added. Neither this patch nor the other uses it, and I don't understand from the description which other keys I could set. Remove it?

+++ og_user_roles.module	6 Jul 2009 18:30:02 -0000
@@ -417,16 +417,20 @@ function og_user_roles_get_roles_by_grou
- * Grant a role or all roles for a user in a group.
+ * Remove a role or all roles for a user in a group.

Please note that this has been fixed in CVS HEAD already.

This review is powered by Dreditor.

hefox’s picture

Why piggyback on hook_og? Maybe cause $op's are out of style now whereas in 2009 it wasn't, but don't see the reasoning on using hook_og, so here's a partch with some simple hooks without $ops.

Here's a simple patch that just adds a simple hook_og_user_roles_add and hook_og_user_roles_delete. $args was a bit confusing on what purpose is served, so renamed it to $contextual_information and added some contextual information for when it's called in hook_og.

My use case is to ensure users only have 1 role and that is_admin is kept in synch with admin role (which currently doesn't always, which may be a letter feature request).

bschilt’s picture

thanks for the patch hefox. The patch originally was created with a custom hook but in comment #3 above, the desire was to use hook_og. To me it doesn't matter. The idea of $args taken from hook_og and would allow other modules to pass data along. Similar how og_subgroups uses $args to determine if propagation is happening or not.

sun’s picture

Status: Postponed » Needs work
+++ b/og_user_roles.module
@@ -411,14 +411,18 @@ function og_user_roles_og($op, $nid, $uid, $args = array()) {
+      $contextual_information = array(

1) The variable should be just $context.

2) If we load any kind of entities, then we want to provide those within $context, too. (like 'group' => $node here)

+++ b/og_user_roles.module
@@ -411,14 +411,18 @@ function og_user_roles_og($op, $nid, $uid, $args = array()) {
+        'og args' => $args,

just 'args'

+++ b/og_user_roles.module
@@ -411,14 +411,18 @@ function og_user_roles_og($op, $nid, $uid, $args = array()) {
+        'og op' => 'user insert',

just 'op' and just 'insert'

bschilt’s picture

The patch in #507498: change how user roles are added and deleted will need to be applied along with this one.