uid == 1 || empty($mlid) || user_access('administer menu_per_role')) { // Admins do not lose access whatever this module would otherwise say // Also, if the menu link identifier is not set, ignore the request 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; } /* * Implementation of hook_form_alter(). */ function menu_per_role_form_alter(&$form, $form_state, $form_id) { if (!user_access('administer menu_per_role')) { return; } if ($form_id == 'menu_edit_item') { $f = &$form; $form['submit']['#weight'] = 10; } if (isset($form['#node']) && $form['#node']->type .'_node_form' == $form_id && isset($form['menu'])) { $f = &$form['menu']; } if (isset($f)) { $default_value_roles = $form['menu']['mlid']['#value'] ? _menu_per_role_get_roles($form['menu']['mlid']['#value'], 0) : array(); $default_value_hide_from_roles = $form['menu']['mlid']['#value'] ? _menu_per_role_get_roles($form['menu']['mlid']['#value'], 1) : array(); $f['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.'), ); $f['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.'), ); $f['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.'), ); $form['#submit'][] = '_menu_per_role_form_submit'; } } /* * Internal function to save the data in our table. */ function _menu_per_role_form_submit($form, &$form_state) { global $db_type; if ($form_state['submitted']) { $mlid = $form_state['values']['menu']['mlid']; if ($mlid) { // hide but to those roles $rids = array(); $roles = isset($form_state['values']['menu_per_role_roles']) ? $form_state['values']['menu_per_role_roles'] : $form_state['values']['menu']['menu_per_role']['menu_per_role_roles']; foreach ($roles as $rid => $checked) { if ($checked) { $rids[] = $rid; } } $rids_str = implode(',', $rids); // show but to those roles $hrids = array(); $roles = isset($form_state['values']['menu_per_role_hide_from_roles']) ? $form_state['values']['menu_per_role_hide_from_roles'] : $form_state['values']['menu']['menu_per_role']['menu_per_role_hide_from_roles']; foreach ($roles as $rid => $checked) { if ($checked) { $hrids[] = $rid; } } $hrids_str = implode(',', $hrids); // save in our table //db_lock_table('menu_per_role'); if ($rids_str || $hrids_str) { db_query("UPDATE {menu_per_role} SET rids = '%s', hrids = '%s' WHERE mlid = %d", $rids_str, $hrids_str, $mlid); if (db_affected_rows() == 0) { // if nothing was affected, the row did not exist yet // (although with MySQL this may fail because db_affected_rows() may only return // rows that have been changed instead of the # of rows that match the WHERE clause.) if ($db_type != 'pgsql') { $insert = !db_result(db_query("SELECT 1 FROM {menu_per_role} WHERE mlid = %d", $mlid)); } else { $insert = TRUE; } if ($insert) { db_query("INSERT INTO {menu_per_role} (mlid, rids, hrids) VALUES (%d, '%s', '%s')", $mlid, $rids_str, $hrids_str); } } } else { // we don't need to save it when empty, instead, remove that completely db_query("DELETE FROM {menu_per_role} WHERE mlid = %d", $mlid); } //db_unlock_tables(); // reset the menus menu_cache_clear_all(); } else if (isset($form_state['values']['menu_per_role_roles'])) { drupal_set_message(t('The menu link identifier was not defined on Submit in Menu per Role. You are most certainly adding a new menu item. For this feature to work when adding a menu item, you must apply the patch defined in node #326210. That patch is included in this module for that purpose.'), 'error'); } } } /* * 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['mlid']) === 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) { $menu_per_role[$row->mlid][0] = explode(',', $row->rids); $menu_per_role[$row->mlid][1] = explode(',', $row->hrids); } } } 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