Index: admin_menu.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/admin_menu/admin_menu.inc,v retrieving revision 1.11 diff -u -p -r1.11 admin_menu.inc --- admin_menu.inc 26 Apr 2008 16:10:09 -0000 1.11 +++ admin_menu.inc 4 Jun 2008 12:04:06 -0000 @@ -40,57 +40,86 @@ function admin_menu_build($mid_admin) { * @see menu_tree_all_data() */ function admin_menu_tree_all_data() { - // chx way. 13/03/2008 sun - // $item_admin = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE link_path = 'admin' AND menu_name = 'navigation'")); $item_admin = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE router_path = 'admin'")); $item_admin = array_merge_recursive($item_admin, menu_get_item('admin')); - - // chx way. 13/03/2008 sun - // $data['tree'] = menu_tree_all_data('navigation', $item_admin); - // return $data['tree']; - - $args = $parents = array($item_admin['mlid']); - $placeholders = implode(', ', array_fill(0, count($args), '%d')); - - // Collect all links as well as all of their children. + $args = $where = array(); + $p = 1; do { - $result = db_query("SELECT mlid FROM {menu_links} WHERE menu_name = '%s' AND has_children = 1 AND plid IN (". $placeholders .') AND mlid NOT IN ('. $placeholders .')', array_merge(array($item_admin['menu_name']), $args, $args)); - $num_rows = FALSE; - while ($item = db_fetch_array($result)) { - $args[] = $item['mlid']; - $num_rows = TRUE; - } - $placeholders = implode(', ', array_fill(0, count($args), '%d')); - } while ($num_rows); - - // Build db_query arguments array. - array_unshift($args, $item_admin['menu_name']); + $where[] = "ml.p$p = %d"; + $args[] = $item_admin["p$p"]; + $p++; + } while ($p < 9 && $item_admin["p$p"] != 0); + $where[] = "ml.p$p != 0"; + $where = implode(' AND ', $where); // Until now, everything seems to be a wanted behaviour of the new menu system // in Drupal 6. However, {menu_links} does not contain any local tasks, and // because of that, it's getting crude now. - - // Select the links from the table, and recursively build the tree. We - // LEFT JOIN since there is no match in {menu_router} for an external - // link. - // Union select all local tasks from {menu_router} - // - that start with 'admin/', - // - using the mlid of the corresponding tab_parent path in {menu_links} as plid, - // - using the depth of the tab_parent path in {menu_links} + 1 as depth. - $types = array(MENU_LOCAL_TASK, MENU_DEFAULT_LOCAL_TASK); - $args = array_merge($args, $types); - $data['tree'] = menu_tree_data(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, ml.* + + // Poor man's locking. + if ($lock = variable_get('admin_menu_lock', 0)) { + while ($lock < time() + 10) { + sleep(1); + } + } + variable_set('admin_menu_lock', time()); + + // Clear old data. + db_query('DELETE FROM {admin_menu}'); + + // Fetch the regular, visible menu tree below 'admin/'. + // @todo Figure out which fields are actually needed for menu building and/or + // theming. Everything else can probably be ignored (doesn't need to be queried). + db_query("INSERT INTO {admin_menu} 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, + ml.menu_name, ml.mlid, ml.plid, ml.link_path, ml.router_path, ml.link_title, ml.options, ml.module, ml.hidden, ml.external, ml.has_children, ml.expanded, ml.weight, ml.depth, ml.customized, ml.p1, ml.p2, ml.p3, ml.p4, ml.p5, ml.p6, ml.p7, ml.p8, ml.p9, ml.updated FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path - WHERE ml.menu_name = '%s' AND ml.plid IN (". $placeholders .") - ) UNION ( - 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, - ml.menu_name, ml.mlid + 100000 as mlid, ml.plid, ml.link_path, ml.router_path, m.title as link_title, ml.options, ml.module, ml.hidden, ml.external, ml.has_children, ml.expanded, ml.weight, ml.depth + 1 as depth, ml.customized, ml.p1, ml.p2, ml.p3, ml.p4, ml.p5, ml.p6, ml.p7, ml.p8, ml.p9, ml.updated - FROM {menu_router} m LEFT JOIN {menu_links} ml ON ml.router_path = m.tab_parent - WHERE ml.router_path REGEXP '[^%%]*' AND m.path LIKE 'admin/%%' AND m.type IN (". db_placeholders($types) .") - ) - ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", $args), $parents); - + WHERE $where", $args); + + // Fetch all local tasks from all administrative menu items using the depth + // of the tab_parent path in {menu_links} + 1 as depth. + $types = array(MENU_LOCAL_TASK, MENU_DEFAULT_LOCAL_TASK); + $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, + ml.menu_name, 0 AS mlid, ml.mlid AS plid, m.path as link_path, m.path as router_path, m.title as link_title, ml.options, ml.module, ml.hidden, ml.external, 0 as has_children, ml.expanded, m.weight, ml.depth + 1 as depth, ml.customized, ml.p1, ml.p2, ml.p3, ml.p4, ml.p5, ml.p6, ml.p7, ml.p8, ml.p9, ml.updated + FROM {menu_router} m + INNER JOIN {menu_links} ml ON ml.router_path = m.tab_parent + WHERE ml.hidden <> -1 AND m.type IN (". db_placeholders($types) .") AND $where", array_merge($types, $args)); + // Assign unique mlids to local tasks, and add them to the previously queried + // menu tree. + $mlid = 100000; + while ($item = db_fetch_array($result)) { + $item['mlid'] = $mlid++; + // Adjust parent id. + $item['p'. $item['depth']] = $item['mlid']; + db_query("INSERT INTO {admin_menu} VALUES ('". implode("','", array_fill(0, count($item), '%s')) ."')", $item); + } + + // Fetch secondary level local tasks. These have its parent in the + // {menu_router} table, which means we have to join the table with itself. + // The parent of the parent item is the link item from the {menu_links} table. + // The item's parent id (plid) needs to be looked up from the {admin_menu} table. + $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, + ml.menu_name, 0 AS mlid, am.mlid AS plid, m.path as link_path, m.path as router_path, m.title as link_title, ml.options, ml.module, ml.hidden, ml.external, 0 as has_children, ml.expanded, m.weight, am.depth + 1 as depth, ml.customized, ml.p1, ml.p2, ml.p3, ml.p4, ml.p5, ml.p6, ml.p7, ml.p8, ml.p9, ml.updated + FROM {menu_router} m + INNER JOIN {menu_router} mp ON (mp.path = m.tab_parent) + INNER JOIN {menu_links} ml ON (ml.router_path = mp.tab_parent) + INNER JOIN {admin_menu} am ON (am.link_path = m.tab_parent) + WHERE ml.hidden <> -1 AND m.type IN (". db_placeholders($types) .") AND $where", array_merge($types, $args)); + while ($item = db_fetch_array($result)) { + $item['mlid'] = $mlid++; + // Adjust parent id of the local task and its parent item. + $item['p'. ($item['depth'] - 1)] = $item['plid']; + $item['p'. $item['depth']] = $item['mlid']; + db_query("INSERT INTO {admin_menu} VALUES ('". implode("','", array_fill(0, count($item), '%s')) ."')", $item); + } + + // @todo Make adjustments to the menu tree here.... + + // Fetch all items, ordered by parent items. + $result = db_query("SELECT * FROM {admin_menu} ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC"); + $data['tree'] = menu_tree_data($result); + + variable_del('admin_menu_lock'); + $data['node_links'] = array(); menu_tree_collect_node_links($data['tree'], $data['node_links']); Index: admin_menu.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/admin_menu/admin_menu.install,v retrieving revision 1.4 diff -u -p -r1.4 admin_menu.install --- admin_menu.install 24 Feb 2008 17:32:47 -0000 1.4 +++ admin_menu.install 4 Jun 2008 12:04:06 -0000 @@ -2,6 +2,243 @@ // $Id: admin_menu.install,v 1.4 2008/02/24 17:32:47 sun Exp $ /** + * Implementation of hook_install(). + */ +function admin_menu_install() { + drupal_install_schema('admin_menu'); +} + +/** + * Implementation of hook_uninstall(). + */ +function admin_menu_uninstall() { + // Remove tables. + drupal_uninstall_schema('admin_menu'); + menu_rebuild(); +} + +// @todo Create a valid scheme. +// @todo Columns that are not needed for menu building and/or theming can +// probably be given a fake definition (CHAR(0)) or even left out. +function admin_menu_schema() { + $schema['admin_menu'] = array( + 'description' => t('Maintains a copy of the menu items for admin menu use.'), + 'fields' => array( + + // Items from table menu_router. + 'load_functions' => array( + 'description' => t('A serialized array of function names (like node_load) to be called to load an object corresponding to a part of the current path.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => ''), + 'to_arg_functions' => array( + 'description' => t('A serialized array of function names (like user_current_to_arg) to be called to replace a part of the router path with another string.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => ''), + 'access_callback' => array( + 'description' => t('The callback which determines the access to this router path. Defaults to user_access.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => ''), + 'access_arguments' => array( + 'description' => t('A serialized array of arguments for the access callback.'), + 'type' => 'text', + 'not null' => FALSE), + 'page_callback' => array( + 'description' => t('The name of the function that renders the page.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => ''), + 'page_arguments' => array( + 'description' => t('A serialized array of arguments for the page callback.'), + 'type' => 'text', + 'not null' => FALSE), + 'title' => array( + 'description' => t('The title for the current page, or the title for the tab if this is a local task.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => ''), + 'title_callback' => array( + 'description' => t('A function which will alter the title. Defaults to t()'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => ''), + 'title_arguments' => array( + 'description' => t('A serialized array of arguments for the title callback. If empty, the title will be used as the sole argument for the title callback.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => ''), + 'type' => array( + 'description' => t('Numeric representation of the type of the menu item, like MENU_LOCAL_TASK.'), + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0), + + // Items from table menu_links. + 'menu_name' => array( + 'description' => t("The menu name. All links with the same menu name (such as 'navigation') are part of the same menu."), + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => ''), + 'mlid' => array( + 'description' => t('The menu link ID (mlid) is the integer primary key.'), + 'type' => 'serial', + 'unsigned' => TRUE, + 'not null' => TRUE), + 'plid' => array( + 'description' => t('The parent link ID (plid) is the mlid of the link above in the hierarchy, or zero if the link is at the top level in its menu.'), + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0), + 'link_path' => array( + 'description' => t('The Drupal path or external path this link points to.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => ''), + 'router_path' => array( + 'description' => t('For links corresponding to a Drupal path (external = 0), this connects the link to a {menu_router}.path for joins.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => ''), + 'link_title' => array( + 'description' => t('The text displayed for the link, which may be modified by a title callback stored in {menu_router}.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => ''), + 'options' => array( + 'description' => t('A serialized array of options to be passed to the url() or l() function, such as a query string or HTML attributes.'), + 'type' => 'text', + 'not null' => FALSE), + 'module' => array( + 'description' => t('The name of the module that generated this link.'), + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => 'system'), + 'hidden' => array( + 'description' => t('A flag for whether the link should be rendered in menus. (1 = a disabled menu item that may be shown on admin screens, -1 = a menu callback, 0 = a normal, visible link)'), + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'size' => 'small'), + 'external' => array( + 'description' => t('A flag to indicate if the link points to a full URL starting with a protocol, like http:// (1 = external, 0 = internal).'), + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'size' => 'small'), + 'has_children' => array( + 'description' => t('Flag indicating whether any links have this link as a parent (1 = children exist, 0 = no children).'), + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'size' => 'small'), + 'expanded' => array( + 'description' => t('Flag for whether this link should be rendered as expanded in menus - expanded links always have their child links displayed, instead of only when the link is in the active trail (1 = expanded, 0 = not expanded)'), + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'size' => 'small'), + 'weight' => array( + 'description' => t('Link weight among links in the same menu at the same depth.'), + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0), + 'depth' => array( + 'description' => t('The depth relative to the top level. A link with plid == 0 will have depth == 1.'), + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'size' => 'small'), + 'customized' => array( + 'description' => t('A flag to indicate that the user has manually created or edited the link (1 = customized, 0 = not customized).'), + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'size' => 'small'), + 'p1' => array( + 'description' => t('The first mlid in the materialized path. If N = depth, then pN must equal the mlid. If depth > 1 then p(N-1) must equal the plid. All pX where X > depth must equal zero. The columns p1 .. p9 are also called the parents.'), + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0), + 'p2' => array( + 'description' => t('The second mlid in the materialized path. See p1.'), + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0), + 'p3' => array( + 'description' => t('The third mlid in the materialized path. See p1.'), + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0), + 'p4' => array( + 'description' => t('The fourth mlid in the materialized path. See p1.'), + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0), + 'p5' => array( + 'description' => t('The fifth mlid in the materialized path. See p1.'), + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0), + 'p6' => array( + 'description' => t('The sixth mlid in the materialized path. See p1.'), + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0), + 'p7' => array( + 'description' => t('The seventh mlid in the materialized path. See p1.'), + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0), + 'p8' => array( + 'description' => t('The eighth mlid in the materialized path. See p1.'), + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0), + 'p9' => array( + 'description' => t('The ninth mlid in the materialized path. See p1.'), + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0), + 'updated' => array( + 'description' => t('Flag that indicates that this link was generated during the update from Drupal 5.'), + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'size' => 'small'), + ), + 'unique keys' => array('mlid' => array('mlid')), + 'indexes' => array( + 'path' => array('link_path'), + ), + ); + return $schema; +} + +/** * #224605: Rebuild cached menu for users. */ function admin_menu_update_5202() { Index: admin_menu.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/admin_menu/admin_menu.module,v retrieving revision 1.43 diff -u -p -r1.43 admin_menu.module --- admin_menu.module 26 Apr 2008 16:10:09 -0000 1.43 +++ admin_menu.module 4 Jun 2008 12:04:06 -0000 @@ -151,15 +151,15 @@ function &admin_menu_get_menu($mid_admin } global $user, $language; - $cid = 'links:admin_menu:all:admin:'. $user->uid .':'. $language->language; - $cache = 0; // cache_get($cid, 'cache_menu'); + $cid = 'links:admin_menu:'. $user->uid .':'. $language->language; + $cache = cache_get($cid, 'cache_menu'); if ($cache && isset($cache->data)) { $_admin_menu = $cache->data; } else { require_once drupal_get_path('module', 'admin_menu') .'/admin_menu.inc'; $_admin_menu = admin_menu_build($mid_admin); - // cache_set($cid, $_admin_menu, 'cache_menu', 0); + cache_set($cid, $_admin_menu, 'cache_menu', 0); } return $_admin_menu; @@ -181,7 +181,7 @@ function admin_menu_tree_output($tree) { // Pull out just the menu items we are going to render so that we // get an accurate count for the first/last classes. foreach ($tree as $data) { - if (!$data['link']['hidden']) { + if ($data['link']['hidden'] != -1) { $items[] = $data; } } @@ -356,7 +356,7 @@ function admin_menu_admin_menu(&$admin_m function admin_menu_form_alter(&$form, $form_state, $form_id) { if ($form_id == 'devel_admin_settings') { // Shift system_settings_form buttons. - $weight = $form['buttons']['#weight']; + $weight = isset($form['buttons']['#weight']) ? $form['buttons']['#weight'] : 0; $form['buttons']['#weight'] = $weight + 1; $form['admin_menu'] = array(