You are here

menu_per_role.module in Menu Per Role 6

Same filename and directory in other branches
  1. 8 menu_per_role.module
  2. 5 menu_per_role.module
  3. 7 menu_per_role.module

Allows restricting access to menu items per role

File

menu_per_role.module
View source
<?php

/**
 * @file
 * Allows restricting access to menu items per role
 */

/*
 * Permission for who can access the menu per role forms.
 */
function menu_per_role_perm() {
  return array(
    'administer menu_per_role',
  );
}

/**
 * Implementation of hook_menu().
 */
function menu_per_role_menu() {
  module_load_include('admin.inc', 'menu_per_role');
  return _menu_per_role_menu();
}

/*
 * Determines access for a give menu item id
 *
 * \warning
 * This function is NOT called automatically up to version 6.10.
 * You need to apply the patch provided in this module so it
 * actually works in older versions. See file:
 *
 * drupal-6.6-menu_per_role.patch
 *
 * \param[in] $item The complete menu item
 *
 * \return NULL if this module does not forbid the viewing of this menu item,
 * FALSE otherwise
 */
function _menu_per_role_access($item) {
  global $user;
  if (empty($item['mlid'])) {

    // no menu indicated, there's nothing to block
    return NULL;
  }
  if ($user->uid == 1) {

    // UID=1 is the all almighty administrator who usually sees everything
    // (a better way would be to mark the menu item with a special class
    // so it could be shown in a different color.)
    if (variable_get('menu_per_role_uid1_see_all', 1)) {
      return NULL;
    }
  }
  elseif (user_access('administer menu_per_role') && variable_get('menu_per_role_admin_see_all', 0)) {

    // The top administrator can also give the menu_per_role administrators
    // access to all the menu items.
    return NULL;
  }

  // if this menu is being edited, make sure the administrator sees all of its items
  if (arg(0) == 'admin' && arg(1) == 'build' && arg(2) == 'menu-customize' && arg(3) == $item['menu_name']) {
    return NULL;
  }

  // check whether this role has visibility access (must be present)
  $rids = _menu_per_role_get_roles($item['mlid'], 0);
  if (!empty($rids) && count(array_intersect($rids, array_keys($user->roles))) == 0) {

    // not permitted by the rids...
    return FALSE;
  }

  // check whether this role has visibility access (must not be present)
  $hrids = _menu_per_role_get_roles($item['mlid'], 1);
  if (!empty($hrids) && count(array_intersect($hrids, array_keys($user->roles))) > 0) {

    // not permitted by the hrids...
    return FALSE;
  }

  // this module is not preventing user from seeing this menu entry
  return NULL;
}

/*
 * Implementation of hook_form_alter().
 */
function menu_per_role_form_alter(&$form, $form_state, $form_id) {
  if (user_access('administer menu_per_role')) {
    module_load_include('admin.inc', 'menu_per_role');
    _menu_per_role_form_alter($form, $form_state, $form_id);
  }
}

/**
 * Implementation of hook_nodeapi().
 *
 * When inserting the menu in a node, the form is "not really there" at
 * the time of the Save. To make it work properly, we need to add this
 * entry. Note also that the submit function does not have access to
 * the 'mlid' yet since it was not yet created.
 *
 * IMPORTANT NOTE: We get executed right after the menu module, which
 * is important since the menu module is the one that generates the
 * 'mlid'. The module would otherwise need to be moved using a weight
 * of 1 or more in the system table.
 */
function menu_per_role_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
  switch ($op) {
    case 'insert':
    case 'update':
      if (!empty($node->menu['mlid']) && user_access('administer menu_per_role')) {
        $form_state = array(
          'submitted' => 1,
          'values' => array(
            'menu' => $node->menu,
            'menu_per_role_roles' => $node->menu['menu_per_role']['menu_per_role_roles'],
            'menu_per_role_hide_from_roles' => $node->menu['menu_per_role']['menu_per_role_hide_from_roles'],
          ),
        );
        module_load_include('admin.inc', 'menu_per_role');
        _menu_per_role_form_submit(NULL, $form_state);
      }
      break;
  }
}

/*
 * When the menu item is being submitted, the core also calls the
 * hook_menu_link_alter(&$item, $menu);
 *
 * By catching that function, we can set the special alter option
 * that will let our module receive a call whenever the menu is
 * ready for display but was not yet displayed. At that time we
 * can mark the access as FALSE.
 */
function menu_per_role_menu_link_alter(&$item, $menu) {

  // TODO: The following marks ALL menu items as alterable.
  //       Any time a menu item is saved, it is marked as
  //       such. I have no clue, at this time, of a way to
  //       avoid such nonsense. Hints welcome!
  $item['options']['alter'] = TRUE;
}

/*
 * Before a menu item gets displayed, the core calls the hook:
 * hook_translated_menu_link_alter(&$item, $map);
 * (but only if $item['options']['alter'] is TRUE)
 *
 * This function is used to alter the access right based on
 * the role definition of the item.
 */
function menu_per_role_translated_menu_link_alter(&$item, $map) {

  // avoid checking the role if the item access is already false
  if ($item['access'] && _menu_per_role_access($item) === FALSE) {
    $item['access'] = FALSE;
  }
}

/**
 * Gets all roles with access to the specified menu item
 * No roles mean that access is granted by this module.
 *
 * $show set to 0 for show to roles, 1 for hide from roles
 */
function _menu_per_role_get_roles($mlid, $show) {
  static $menu_per_role;
  if (!isset($menu_per_role)) {

    // read all the data ONCE, it is likely very small
    $menu_per_role = array();
    $result = db_query("SELECT * FROM {menu_per_role}");
    while ($row = db_fetch_object($result)) {
      if ($row->rids || $row->hrids) {
        if ($row->rids) {
          $menu_per_role[$row->mlid][0] = explode(',', $row->rids);
        }
        else {
          $menu_per_role[$row->mlid][0] = array();
        }
        if ($row->hrids) {
          $menu_per_role[$row->mlid][1] = explode(',', $row->hrids);
        }
        else {
          $menu_per_role[$row->mlid][1] = array();
        }
      }
    }
  }
  if (isset($menu_per_role[$mlid])) {
    return $menu_per_role[$mlid][$show];
  }

  // not defined, everyone has the right to use it
  return array();
}

// vim: ts=2 sw=2 et syntax=php

Functions

Namesort descending Description
menu_per_role_form_alter
menu_per_role_menu Implementation of hook_menu().
menu_per_role_menu_link_alter
menu_per_role_nodeapi Implementation of hook_nodeapi().
menu_per_role_perm
menu_per_role_translated_menu_link_alter
_menu_per_role_access
_menu_per_role_get_roles Gets all roles with access to the specified menu item No roles mean that access is granted by this module.