menu_per_role.module in Menu Per Role 7
Same filename and directory in other branches
Allows restricting access to menu items per role.
File
menu_per_role.moduleView source
<?php
/**
* @file
* Allows restricting access to menu items per role.
*/
/**
* Implements hook_help().
*/
function menu_per_role_help($path, $arg) {
switch ($path) {
case 'admin/help#menu_per_role':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Menu Per Role module allows you to restrict access of menu items per roles.') . '</p>';
$output .= '<h3>' . t('Configuration') . '</h3>';
$output .= '<p>' . t('Just activate the Menu Per Role module and edit a menu item as usual. There will be one or two fieldsets, depending on the configuration of the module, that allows you to restrict access by role.') . '</p>';
$output .= '<p>' . t("If you don't check any roles the default access permissions will be kept. Otherwise the module will additionally restrict access to the chosen user roles.") . '</p>';
return $output;
}
}
/**
* Implements hook_permission().
*/
function menu_per_role_permission() {
$permissions = array();
$permissions['administer menu_per_role'] = array(
'title' => t('Administer Menu Per Role'),
'description' => t('Permission for who can access the Menu Per Role forms.'),
);
return $permissions;
}
/**
* Implements hook_menu().
*/
function menu_per_role_menu() {
$menu = array();
$menu['admin/config/system/menu_per_role'] = array(
'title' => 'Menu Per Role',
'description' => 'Settings for the Menu Per Role module',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'menu_per_role_settings_form',
),
'access arguments' => array(
'administer menu_per_role',
),
'file' => 'menu_per_role.admin.inc',
);
return $menu;
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function menu_per_role_form_menu_edit_item_alter(&$form, &$form_state, $form_id) {
if (!user_access('administer menu_per_role')) {
return;
}
$default_value_roles = $form['mlid']['#value'] ? _menu_per_role_get_roles($form['mlid']['#value'], 0) : array();
$default_value_hide_from_roles = $form['mlid']['#value'] ? _menu_per_role_get_roles($form['mlid']['#value'], 1) : array();
$form['menu_per_role'] = array(
'#type' => 'fieldset',
'#title' => t('Restrict item visibility'),
'#collapsible' => TRUE,
'#collapsed' => count($default_value_roles) + count($default_value_hide_from_roles) == 0,
'#weight' => 5,
'#description' => t('Check to know whether the user has proper visibility permissions to see this menu item. Note that both checks are always performed.'),
'#tree' => TRUE,
);
$form['menu_per_role']['menu_per_role_roles'] = array(
'#type' => 'checkboxes',
'#title' => t('Show menu item only to selected roles'),
'#options' => user_roles(),
'#default_value' => $default_value_roles,
'#description' => t('Check no role to leave the access permission to the default. A user who is not part of at least one of the selected roles will not see this menu item.'),
);
$form['menu_per_role']['menu_per_role_hide_from_roles'] = array(
'#type' => 'checkboxes',
'#title' => t('Hide menu item from selected roles'),
'#options' => user_roles(),
'#default_value' => $default_value_hide_from_roles,
'#description' => t('Check no role to leave the access permission to the default. A user who is part of any one of these roles will not see this menu item.'),
);
}
/**
* Implements hook_menu_link_insert().
*/
function menu_per_role_menu_link_insert($link) {
if (isset($link['menu_per_role']) && user_access('administer menu_per_role')) {
// Hide but to those roles.
$rids_str = _menu_per_role_serialize_rids($link['menu_per_role']['menu_per_role_roles']);
// Show but to those roles.
$hrids_str = _menu_per_role_serialize_rids($link['menu_per_role']['menu_per_role_hide_from_roles']);
$fields = array(
'rids' => $rids_str,
'hrids' => $hrids_str,
'mlid' => $link['mlid'],
);
drupal_write_record('menu_per_role', $fields);
}
}
/**
* Implements hook_menu_link_update().
*/
function menu_per_role_menu_link_update($link) {
if (isset($link['menu_per_role']) && user_access('administer menu_per_role')) {
// Hide but to those roles.
$rids_str = _menu_per_role_serialize_rids($link['menu_per_role']['menu_per_role_roles']);
// Show but to those roles.
$hrids_str = _menu_per_role_serialize_rids($link['menu_per_role']['menu_per_role_hide_from_roles']);
$fields = array(
'rids' => $rids_str,
'hrids' => $hrids_str,
);
$count = db_select('menu_per_role')
->condition('mlid', $link['mlid'])
->countQuery()
->execute()
->fetchField();
if ($count == 0) {
$fields['mlid'] = $link['mlid'];
db_insert('menu_per_role')
->fields($fields)
->execute();
}
else {
db_update('menu_per_role')
->fields($fields)
->condition('mlid', $link['mlid'])
->execute();
}
}
}
/**
* Implements hook_menu_link_delete().
*/
function menu_per_role_menu_link_delete($link) {
// Delete the record from our table.
db_delete('menu_per_role')
->condition('mlid', $link['mlid'])
->execute();
}
/**
* Implements hook_menu_link_alter().
*
* 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) {
// 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!
menu_per_role_menu_link_update($item);
$item['options']['alter'] = TRUE;
}
/**
* Implements hook_translated_menu_link_alter().
*
* 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['mlid']) === FALSE) {
$item['access'] = FALSE;
}
}
/**
* Determines access for a given menu item id.
*
* @param int $mlid
* The menu item identifier.
*
* @return bool|null
* NULL if this module does not forbid the viewing of this menu item, FALSE
* otherwise.
*/
function _menu_per_role_access($mlid) {
global $user;
if (empty($mlid)) {
return NULL;
}
// If menu is being edited allow user to see it in full.
if (arg(0) == 'admin' && arg(1) == 'structure' && arg(2) == 'menu') {
return NULL;
}
// Check whether this role has visibility access (must be present).
$rids = _menu_per_role_get_roles($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($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;
}
/**
* Turn the given roles into a serialized string of rids or hrids.
*
* @param array $roles
* An array of roles as passed from the appropriate keys from
* $form_state['values'] during a form submit.
*
* @return string
* A string of the serialized rids.
*/
function _menu_per_role_serialize_rids(array $roles) {
$rids = array();
foreach ($roles as $rid => $checked) {
if ($checked) {
$rids[] = $rid;
}
}
return implode(',', $rids);
}
/**
* Turn a serialized string of rids or hrids into an array of rids or hrids.
*
* @param string $rids
* The serialized string to unserialize.
*
* @return array
* An array of rids.
*/
function _menu_per_role_unserialize_rids($rids) {
return explode(',', $rids);
}
/**
* Gets all roles with access to the specified menu item.
*
* No roles mean that access is granted by this module.
*
* @param int $mlid
* The menu link id.
* @param int $show
* Set to 0 for show to roles, 1 for hide from roles.
*
* @return array
* An array of 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_select('menu_per_role', 'mpr')
->fields('mpr')
->execute()
->fetchAll();
foreach ($result as $row) {
if ($row->rids || $row->hrids) {
if ($row->rids) {
$menu_per_role[$row->mlid][0] = _menu_per_role_unserialize_rids($row->rids);
}
else {
$menu_per_role[$row->mlid][0] = array();
}
if ($row->hrids) {
$menu_per_role[$row->mlid][1] = _menu_per_role_unserialize_rids($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();
}
Functions
Name | Description |
---|---|
menu_per_role_form_menu_edit_item_alter | Implements hook_form_FORM_ID_alter(). |
menu_per_role_help | Implements hook_help(). |
menu_per_role_menu | Implements hook_menu(). |
menu_per_role_menu_link_alter | Implements hook_menu_link_alter(). |
menu_per_role_menu_link_delete | Implements hook_menu_link_delete(). |
menu_per_role_menu_link_insert | Implements hook_menu_link_insert(). |
menu_per_role_menu_link_update | Implements hook_menu_link_update(). |
menu_per_role_permission | Implements hook_permission(). |
menu_per_role_translated_menu_link_alter | Implements hook_translated_menu_link_alter(). |
_menu_per_role_access | Determines access for a given menu item id. |
_menu_per_role_get_roles | Gets all roles with access to the specified menu item. |
_menu_per_role_serialize_rids | Turn the given roles into a serialized string of rids or hrids. |
_menu_per_role_unserialize_rids | Turn a serialized string of rids or hrids into an array of rids or hrids. |