Index: modules/system/system.module =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.module,v retrieving revision 1.735 diff -u -p -r1.735 system.module --- modules/system/system.module 3 Aug 2009 06:06:23 -0000 1.735 +++ modules/system/system.module 4 Aug 2009 17:10:19 -0000 @@ -1552,14 +1552,26 @@ function system_block_view($delta = '') */ function system_admin_menu_block($item) { $cache = &drupal_static(__FUNCTION__, array()); + + // This function is called on every page request if administrative links are + // displayed, so we cache by path to improve the performance of + // system_admin_menu_block_access(). While path is not guaranteed to be + // unique if users configure their administrative menu using the menu + // interface, we don't support two top level items with the same path + // here since this would require an additional query, or duplicate cache to + // be implemented. + if (isset($cache[$item['path']])) { + return $cache[$item['path']]; + } + global $user; + $cid = 'system:admin:links:' . implode('|', array_keys($user->roles)) . $item['path']; + if ($cached = cache_get($cid, 'cache_menu')) { + $cache[$item['path']] = $cached->data; + return $cached->data; + } if (!isset($item['mlid'])) { $item += db_query("SELECT mlid, menu_name FROM {menu_links} ml WHERE ml.router_path = :path AND module = 'system'", array(':path' => $item['path']))->fetchAssoc(); } - - if (isset($cache[$item['mlid']])) { - return $cache[$item['mlid']]; - } - $content = array(); $result = db_query(" SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type, m.description, ml.* @@ -1581,7 +1593,8 @@ function system_admin_menu_block($item) $content[(50000 + $link['weight']) . ' ' . $link['title'] . ' ' . $link['mlid']] = $link; } ksort($content); - $cache[$item['mlid']] = $content; + cache_set($cid, $content, 'cache_menu'); + $cache[$item['path']] = $content; return $content; } @@ -2926,6 +2939,21 @@ function system_goto_action($object, $co } /** + * Implementation of hook_user_role_update(). + */ +function system_user_role_update($role) { + // Clear the system_admin_menu_block() cache. + cache_clear_all('system:admin:links:', 'cache_menu', TRUE); +} + +/** + * Implementation of hook_user_role_delete(). + */ +function system_user_role_delete() { + cache_clear_all('system:admin:links:', 'cache_menu', TRUE); +} + +/** * Implement a Drupal action. * Blocks the user's IP address. */ Index: modules/toolbar/toolbar.module =================================================================== RCS file: /cvs/drupal/drupal/modules/toolbar/toolbar.module,v retrieving revision 1.4 diff -u -p -r1.4 toolbar.module --- modules/toolbar/toolbar.module 28 Jul 2009 10:35:56 -0000 1.4 +++ modules/toolbar/toolbar.module 4 Aug 2009 17:10:24 -0000 @@ -111,6 +111,17 @@ function toolbar_build() { * Get only the top level items below the 'admin' path. */ function toolbar_get_menu_tree() { + global $user; + // Since generating the key can take 25% of page execution time, cache this + // for each combination of user roles. This guarantees a unique set of + // permissions for the minimum number of cache entries. We use the + // {cache_menu} bin to ensure this cache is cleared when the menu is updated. + // Also use the same $cid prefix as system_admin_menu_block() since we want + // this to be cleared in the same situations (changes to role permissions). + $cid = 'system:admin:links:toolbar:' . implode('|', array_keys($user->roles)); + if ($cached = cache_get($cid, 'cache_menu')) { + return $cached->data; + } $tree = menu_tree_all_data('management'); foreach ($tree as $item) { if ($item['link']['link_path'] == 'admin' && !empty($item['below'])) { @@ -124,6 +135,7 @@ function toolbar_get_menu_tree() { // Get rid of subitems to have a leaner data structure. unset($tree[$key]['below']); } + cache_set($cid, $tree, 'cache_menu'); return $tree; } Index: modules/user/user.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.admin.inc,v retrieving revision 1.66 diff -u -p -r1.66 user.admin.inc --- modules/user/user.admin.inc 31 Jul 2009 19:01:03 -0000 1.66 +++ modules/user/user.admin.inc 4 Aug 2009 17:10:24 -0000 @@ -659,7 +659,8 @@ function user_admin_permissions($form_st * @see user_admin_permissions() */ function user_admin_permissions_submit($form, &$form_state) { - foreach ($form_state['values']['role_names'] as $rid => $name) { + $roles = $form_state['values']['role_names']; + foreach ($roles as $rid => $name) { $checked = array_filter($form_state['values'][$rid]); // Delete existing permissions for the role. This handles "unchecking" checkboxes. db_delete('role_permission') @@ -673,10 +674,14 @@ function user_admin_permissions_submit($ )); } $query->execute(); + // Allow modules to respond to changes to user roles. + module_invoke_all('user_role_update', array('rid' => $rid, 'name' => $name)); } drupal_set_message(t('The changes have been saved.')); + // Allow modules to respond to changes to roles. + // Clear the cached pages and blocks. cache_clear_all(); } @@ -790,11 +795,14 @@ function user_admin_role_validate($form, } function user_admin_role_submit($form, &$form_state) { + $name = isset($form_state['values']['name']) ? $form_state['values']['name'] : FALSE; + $rid = isset($form_state['values']['name']) ? $form_state['values']['name'] : FALSE; if ($form_state['values']['op'] == t('Save role')) { db_update('role') - ->fields(array('name' => $form_state['values']['name'])) - ->condition('rid', $form_state['values']['rid']) + ->fields(array('name' => $name)) + ->condition('rid', $rid) ->execute(); + module_invoke_all('user_role_update', array('rid' => $rid, 'name' => $name)); drupal_set_message(t('The role has been renamed.')); } elseif ($form_state['values']['op'] == t('Delete role')) { @@ -809,12 +817,15 @@ function user_admin_role_submit($form, & ->condition('rid', $form_state['values']['rid']) ->execute(); + module_invoke_all('user_role_delete', $rid); + drupal_set_message(t('The role has been deleted.')); } elseif ($form_state['values']['op'] == t('Add role')) { - db_insert('role') + $rid = db_insert('role') ->fields(array('name' => $form_state['values']['name'])) ->execute(); + module_invoke_all('user_role_insert', array('rid' => $rid, 'name' => $name); drupal_set_message(t('The role has been added.')); } $form_state['redirect'] = 'admin/settings/roles'; Index: modules/user/user.api.php =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.api.php,v retrieving revision 1.8 diff -u -p -r1.8 user.api.php --- modules/user/user.api.php 31 Jul 2009 19:01:03 -0000 1.8 +++ modules/user/user.api.php 4 Aug 2009 17:10:24 -0000 @@ -263,6 +263,39 @@ function hook_user_categories() { )); } +/** + * Act on user role creation. + * + * @param $role + * An array containing the role ID and name. + */ +function user_role_insert($role) { + db_insert('my_table')->fields(array('rid' => $role['rid'], 'my_field' => $role['name']))->execute(); +} + +/** + * Act on user role updates. + * + * @param $role + * An array containing the role ID and name. + */ +function hook_user_role_update($role) { + // Invalidate the system_admin_menu_block() cache, since this + // depends on user permissions. + cache_clear_all('system:admin:links:', 'cache_menu', TRUE); +} + +/** + * Act on user role deletion. + * + * @param $rid + * The role ID. + */ +function system_user_role_delete($rid) { + // Invalidate the system_admin_menu_bock() cache since this + // depends on user roles for the cache key. + cache_clear_all('system:admin:links:', 'cache_menu', TRUE); +} /** * @} End of "addtogroup hooks".