You are here

Drupal 7 - Adding Roles to Users Dynamically

This post builds upon a previous post: Drupal 7 - Adding Roles

Now that we can create our own roles with pre-defined sets of permissions, what can we do with them? Well, what if you had a web-site that assigned user roles based on how long the user had been a member? New users would simply be authenticated users. Once a new user had been a member of the site for a week they would be granted the role 'newb' which would allow them to view special content and use the search widget. After being a member for a month that same user would be promoted to the role of 'pangus' with permission to create, edit, and delete special content as well as permission to use advanced search feature. How would you go about implementing that? Well, just like the previous example, we need to define the hook_install() and hook_uninstall() functions:


/**
 * Implements hook_install().
 */
function simple_user_roles_install() {
  // create any roles we will be using
  simple_user_roles_add_role('newb', 1);
  simple_user_roles_add_role('pangus', 1);
  // add permissions to the new roles
  $newb_permissions = array(
    'search content',
    'view simple content type',
  );
  $pangus_permissions = array(
    'search content',
    'use advanced search',
    'view simple content type',
    'create simple content type',
    'edit simple content type',
    'delete simple content type',
  );
  simple_user_roles_add_permissions('newb', $newb_permissions);
  simple_user_roles_add_permissions('pangus', $pangus_permissions);
}
/**
 * Implements hook_uninstall().
 */
function simple_user_roles_uninstall() {
  // remove the roles we created
  user_role_delete('newb');
  user_role_delete('pangus');
}

These hooks add and set-up the roles we will be using or removing them on uninstall, just like they do in the previous example. Now we need to set up the code which will handle assigning the correct role to users. For this functionality we want to tie into the Cron job functionality of Drupal and implement hook_cron():


/**
 * Implements hook_cron().
 */
function simple_user_roles_cron()  {
  // get a list of active users
  $results = db_select('users', 'u')
    ->fields('u', array('uid', 'created'))
    ->condition('u.status', 1)
    ->execute();
  // limit the list of users to those who do not have the roles pangus or administrator
  $users = array();
  foreach ($results as $user)  {
    // get any roles assigned to this user
    $roles = db_select('users_roles', 'r')
      ->fields('r', array('rid'))
      ->condition('r.uid', $user->uid)
      ->execute();
    if (!$roles)  {
      $users[] = $user;
    } 
    else  {
      $add_role = TRUE;
      foreach ($roles as $role)  {
        $role_name = user_role_load($role->rid)->name;
        if  ($role_name == 'pangus' || $role_name == 'administrator')  {
          $add_role = FALSE;
        } // end if
      } // end foreach
      if ($add_role)  {
        $users[] = $user;
      } // end if
    } // end if
  } // end foreach
  // some convenience vars
  $newb_rid = user_role_load_by_name('newb')->rid;
  $week = 60 * 60 * 24 * 7;
  $month = 60 * 60 * 24 * 30;
  // get the current time
  $time = time();
  // foreach user
  foreach ($users as $user)  {
    // how long has the user been a member?
    $time_length = $time - $user->created;
    // if it has it been longer than a week but less than a month
    if ($time_length >= $week && $time_length < $month)  {
      // add the newb role if they do not have it already
      simple_user_roles_add_role_to_user('newb', $user->uid);
    } 
    elseif ($time_length >= $month) {
      //  if it has been longer than a month
      // remove the newb role
      $sql = "DELETE FROM {users_roles} WHERE uid=:uid AND rid=:rid";
      $delete = db_query($sql, array(':uid' => $user->uid, ':rid' => $newb_rid));
      // add the pangus role
      simple_user_roles_add_role_to_user('pangus', $user->uid);
    } // end if
  } // end foreach
}

Let's step through what's going on above. First thing, we need to get a list of the active users on the site and remove any users from the list who already have the 'pangus' or 'administrator' role assigned to them. Next we need to find out how long each user in our list has been member. If the user has been a member for a week or longer but less than a month we assign the 'newb' role to them if it has not been assigned already. If a user has been a member for a month or longer we remove the 'newb' role and add the 'pangus' role if it hasn't been assigned already. That's the bulk of it. We do have a few helper functions which assist with adding and creating roles:


/**
 *  Adds a new role
 *  @machine_name - the name of the role to be added
 *  @weight - the optional display weight for role
 */
function simple_user_roles_add_role($machine_name, $weight = 0)  {
  $role = new stdClass();
  $role->name = $machine_name;
  $role->weight = $weight;
  if (!user_role_load_by_name($role->name))  {
    user_role_save($role);
  }
}
/**
 *  Adds permissions to a role
 *  @role_name - the name of the role to receive an update
 *  @permissions - the array of permissions to add
 */
function simple_user_roles_add_permissions($role_name, $permissions)  {
  $role = user_role_load_by_name($role_name);
  user_role_grant_permissions($role->rid, $permissions);
}
/**
 * Adds a role to a user
 * @role_name - the machine name for the role to be added
 * @uid - the {user}.uid for the user being updated
 */
function simple_user_roles_add_role_to_user($role_name, $uid)  {
  $results = db_select('users_roles', 'ur')
    ->fields('ur', array('rid'))
    ->condition('ur.uid', $uid)
    ->execute();
  $_add_to_user = TRUE;
  if ($results->rowCount() > 0)  {
    // check to see if the user already has this role assigned to them
    foreach ($results as $rid)  {
      $name = user_role_load($rid->rid)->name;
      if ($name == $role_name) {
        $_add_to_user = FALSE;
      }
    }
  }
  if ($_add_to_user)  {
    $rid = user_role_load_by_name($role_name)->rid;
    $insert = db_insert('users_roles')
      ->fields(array(
        'uid' => $uid,
        'rid' => $rid,
      ))
      ->execute();
  }
}

The simple_user_roles_add_role() and simple_user_roles_add_permissions() are the same as they were in the last post. We use simple_user_roles_add_role_to_user() to add a role to a user if they have not already had it assigned to them. It take two parameters: $role_name - the machine name for the role to be added and $uid - the {user}.uid for the user being updated. Lastly here's the module.info file:


name = Simple User Roles
description = A demonstration on adding roles to users dynamically based on how long they have been a site member
package = Andy Pangus Examples
core = 7.x
dependencies[] = search
dependencies[] = simple_content_type
files[] = simple_user_roles.install
files[] = simple_user_roles.module

Before testing we need to create some test users. We will need seven users in total to test all the use cases:

  • New user - a user who has just joined the site
  • One week - a user who has been a site member for a week
  • Four weeks - a user who has been a site member for four weeks and has no roles assigned to them
  • Four weeks with 'newb' role - a user who has been a site member for four weeks and has the 'newb' role assigned to them
  • One month - a user who has been a site member for a month and has no roles assigned to them
  • One month with 'newb' role - a user who has been a site member for a month and has the 'newb' role assigned to them
  • One month with 'pangus' role - a user who has been a site member for a month and has the 'pangus' role assigned to them

Adding some users to test functionality

Once we have created the users for testing we need to modify the 'created' field in the 'users' table of the database for each user (I use phpMyAdmin) to reflect the amount of time each test user should have been a member of the site. This should be calculated the same as you would calculate a UNIX timestamp. For example, the value for one week would be 60 seconds * 60 minutes * 24 hours * 7 days. You take that value and subtract it from the 'created' timestamp and that should give you the new timestamp to use:

Update the users' account creation times

Now that the users are all set up correctly we need to run Cron by going to admin/config/system/cron and clicking the 'Run Cron' button:

What oour test users look like port-cron

And there you have it, now all site users have the correct role based on the length of time they have been a member of your site. That's just one case where you could add roles to users programatically I'm sure there are many others.

Download the source for this example.

Tags: