- Patch #154470 by pwolanin et al: optimize menu queries and indices.
parent
541c9673b4
commit
15c68075d9
|
@ -157,13 +157,13 @@ define('MENU_SITE_OFFLINE', 4);
|
|||
/**
|
||||
* The maximum number of path elements for a menu callback
|
||||
*/
|
||||
define('MENU_MAX_PARTS', 6);
|
||||
define('MENU_MAX_PARTS', 7);
|
||||
|
||||
|
||||
/**
|
||||
* The maximum depth of a menu links tree - matches the number of p columns.
|
||||
*/
|
||||
define('MENU_MAX_DEPTH', 6);
|
||||
define('MENU_MAX_DEPTH', 9);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -187,7 +187,9 @@ define('MENU_MAX_DEPTH', 6);
|
|||
* part of the path. If the bit is 1, then it represents the original
|
||||
* value while 0 means wildcard. If the path is node/12/edit/foo
|
||||
* then the 1011 bitstring represents node/%/edit/foo where % means that
|
||||
* any argument matches that part.
|
||||
* any argument matches that part. We limit ourselves to using binary
|
||||
* numbers that correspond the patterns of wildcards of router items that
|
||||
* actually exists. This list of 'masks' is built in menu_rebuild().
|
||||
*
|
||||
* @param $parts
|
||||
* An array of path parts, for the above example
|
||||
|
@ -197,17 +199,25 @@ define('MENU_MAX_DEPTH', 6);
|
|||
* simply contain as many '%s' as the ancestors.
|
||||
*/
|
||||
function menu_get_ancestors($parts) {
|
||||
$n1 = count($parts);
|
||||
$number_parts = count($parts);
|
||||
$placeholders = array();
|
||||
$ancestors = array();
|
||||
$end = (1 << $n1) - 1;
|
||||
$length = $n1 - 1;
|
||||
for ($i = $end; $i > 0; $i--) {
|
||||
$length = $number_parts - 1;
|
||||
$end = (1 << $number_parts) - 1;
|
||||
$masks = variable_get('menu_masks', array());
|
||||
// Only examine patterns that actually exist as router items (the masks).
|
||||
foreach ($masks as $i) {
|
||||
if ($i > $end) {
|
||||
// Only look at masks that are not longer than the path of interest.
|
||||
continue;
|
||||
}
|
||||
elseif ($i < (1 << $length)) {
|
||||
// We have exhausted the masks of a given length, so decrease the length.
|
||||
--$length;
|
||||
}
|
||||
$current = '';
|
||||
$count = 0;
|
||||
for ($j = $length; $j >= 0; $j--) {
|
||||
if ($i & (1 << $j)) {
|
||||
$count++;
|
||||
$current .= $parts[$length - $j];
|
||||
}
|
||||
else {
|
||||
|
@ -217,11 +227,6 @@ function menu_get_ancestors($parts) {
|
|||
$current .= '/';
|
||||
}
|
||||
}
|
||||
// If the number was like 10...0 then the next number will be 11...11,
|
||||
// one bit less wide.
|
||||
if ($count == 1) {
|
||||
$length--;
|
||||
}
|
||||
$placeholders[] = "'%s'";
|
||||
$ancestors[] = $current;
|
||||
}
|
||||
|
@ -380,7 +385,7 @@ function _menu_check_access(&$item, $map) {
|
|||
/**
|
||||
* Localize the item title using t() or another callback.
|
||||
*/
|
||||
function _menu_item_localize(&$item) {
|
||||
function _menu_item_localize(&$item, $map) {
|
||||
// Translate the title to allow storage of English title strings in the
|
||||
// database, yet display of them in the language required by the current
|
||||
// user.
|
||||
|
@ -392,7 +397,7 @@ function _menu_item_localize(&$item) {
|
|||
$item['title'] = t($item['title']);
|
||||
}
|
||||
else {
|
||||
$item['title'] = t($item['title'], unserialize($item['title_arguments']));
|
||||
$item['title'] = t($item['title'], menu_unserialize($item['title_arguments'], $map));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -400,7 +405,7 @@ function _menu_item_localize(&$item) {
|
|||
$item['title'] = $callback($item['title']);
|
||||
}
|
||||
else {
|
||||
$item['title'] = call_user_func_array($callback, unserialize($item['title_arguments']));
|
||||
$item['title'] = call_user_func_array($callback, menu_unserialize($item['title_arguments'], $map));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -460,7 +465,7 @@ function _menu_translate(&$router_item, $map, $to_arg = FALSE) {
|
|||
$router_item['href'] = implode('/', $link_map);
|
||||
_menu_check_access($router_item, $map);
|
||||
|
||||
_menu_item_localize($router_item);
|
||||
_menu_item_localize($router_item, $map);
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
@ -531,8 +536,8 @@ function _menu_link_translate(&$item) {
|
|||
_menu_check_access($item, $map);
|
||||
}
|
||||
// If the link title matches that of a router item, localize it.
|
||||
if (isset($item['title']) && ($item['title'] == $item['link_title'])) {
|
||||
_menu_item_localize($item);
|
||||
if (!empty($item['title']) && (($item['title'] == $item['link_title']) || ($item['title_callback'] != 't'))) {
|
||||
_menu_item_localize($item, $map);
|
||||
}
|
||||
else {
|
||||
$item['title'] = $item['link_title'];
|
||||
|
@ -602,18 +607,16 @@ function menu_tree_output($tree) {
|
|||
* A fully loaded menu link, or NULL. If a link is supplied, only the
|
||||
* path to root will be included in the returned tree- as if this link
|
||||
* represented the current page in a visible menu.
|
||||
* @param $show_hidden
|
||||
* Show disabled links (such as suggested menu items).
|
||||
* @return
|
||||
* An tree of menu links in an array, in the order they should be rendered.
|
||||
*/
|
||||
function menu_tree_all_data($menu_name = 'navigation', $item = NULL, $show_hidden = FALSE) {
|
||||
function menu_tree_all_data($menu_name = 'navigation', $item = NULL) {
|
||||
static $tree = array();
|
||||
|
||||
// Use $mlid as a flag for whether the data being loaded is for the whole tree.
|
||||
$mlid = isset($item['mlid']) ? $item['mlid'] : 0;
|
||||
// Generate the cache ID.
|
||||
$cid = 'links:'. $menu_name .':all:'. $mlid .':'. (int)$show_hidden;
|
||||
$cid = 'links:'. $menu_name .':all:'. $mlid;
|
||||
|
||||
if (!isset($tree[$cid])) {
|
||||
// If the static variable doesn't have the data, check {cache_menu}.
|
||||
|
@ -626,7 +629,10 @@ function menu_tree_all_data($menu_name = 'navigation', $item = NULL, $show_hidde
|
|||
if ($mlid) {
|
||||
// The tree is for a single item, so we need to match the values in its
|
||||
// p columns and 0 (the top level) with the plid values of other links.
|
||||
$args = array(0, $item['p1'], $item['p2'], $item['p3'], $item['p4'], $item['p5']);
|
||||
$args = array(0);
|
||||
for ($i = 1; $i < MENU_MAX_DEPTH; $i++) {
|
||||
$args[] = $item["p$i"];
|
||||
}
|
||||
$args = array_unique($args);
|
||||
$placeholders = implode(', ', array_fill(0, count($args), '%d'));
|
||||
$where = ' AND ml.plid IN ('. $placeholders .')';
|
||||
|
@ -642,22 +648,19 @@ function menu_tree_all_data($menu_name = 'navigation', $item = NULL, $show_hidde
|
|||
array_unshift($args, $menu_name);
|
||||
// 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. We need to select links that are visible or hidden
|
||||
// (ml.hidden >= 0), but not callbacks (ml.hidden < 0), so that we can
|
||||
// later exclude all the children of a hidden item.
|
||||
// No need to order by p6 - there is a sort by weight later.
|
||||
// link.
|
||||
$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.*
|
||||
FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path
|
||||
WHERE ml.menu_name = '%s'". $where ." AND ml.hidden >= 0
|
||||
ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC", $args), $parents);
|
||||
WHERE ml.menu_name = '%s'". $where ."
|
||||
ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", $args), $parents);
|
||||
$data['node_links'] = array();
|
||||
menu_tree_collect_node_links($data['tree'], $data['node_links']);
|
||||
// Cache the data.
|
||||
cache_set($cid, $data, 'cache_menu');
|
||||
}
|
||||
// Check access for the current user to each item in the tree.
|
||||
menu_tree_check_access($data['tree'], $data['node_links'], $show_hidden);
|
||||
menu_tree_check_access($data['tree'], $data['node_links']);
|
||||
$tree[$cid] = $data['tree'];
|
||||
}
|
||||
|
||||
|
@ -697,17 +700,18 @@ function menu_tree_page_data($menu_name = 'navigation') {
|
|||
// Build and run the query, and build the tree.
|
||||
if ($item['access']) {
|
||||
// Check whether a menu link exists that corresponds to the current path.
|
||||
$parents = db_fetch_array(db_query("SELECT p1, p2, p3, p4, p5, p6 FROM {menu_links} WHERE menu_name = '%s' AND link_path = '%s'", $menu_name, $item['href']));
|
||||
$parents = db_fetch_array(db_query("SELECT p1, p2, p3, p4, p5, p6, p7, p8 FROM {menu_links} WHERE menu_name = '%s' AND link_path = '%s'", $menu_name, $item['href']));
|
||||
|
||||
if (empty($parents)) {
|
||||
// If no link exists, we may be on a local task that's not in the links.
|
||||
// TODO: Handle the case like a local task on a specific node in the menu.
|
||||
$parents = db_fetch_array(db_query("SELECT p1, p2, p3, p4, p5, p6 FROM {menu_links} WHERE menu_name = '%s' AND link_path = '%s'", $menu_name, $item['tab_root']));
|
||||
$parents = db_fetch_array(db_query("SELECT p1, p2, p3, p4, p5, p6, p7, p8 FROM {menu_links} WHERE menu_name = '%s' AND link_path = '%s'", $menu_name, $item['tab_root']));
|
||||
}
|
||||
// We always want all the top-level links with plid == 0.
|
||||
$parents[] = '0';
|
||||
|
||||
$args = $parents = array_unique($parents);
|
||||
// Use array_values() so that the indices are numeric for array_merge().
|
||||
$args = $parents = array_unique(array_values($parents));
|
||||
$placeholders = implode(', ', array_fill(0, count($args), '%d'));
|
||||
$expanded = variable_get('menu_expanded', array());
|
||||
// Check whether the current menu has any links set to be expanded.
|
||||
|
@ -715,7 +719,7 @@ function menu_tree_page_data($menu_name = 'navigation') {
|
|||
// Collect all the links set to be expanded, and then add all of
|
||||
// their children to the list as well.
|
||||
do {
|
||||
$result = db_query("SELECT mlid FROM {menu_links} WHERE expanded != 0 AND has_children != 0 AND menu_name = '%s' AND plid IN (". $placeholders .') AND mlid NOT IN ('. $placeholders .')', array_merge(array($menu_name), $args, $args));
|
||||
$result = db_query("SELECT mlid FROM {menu_links} WHERE menu_name = '%s' AND expanded = 1 AND has_children = 1 AND plid IN (". $placeholders .') AND mlid NOT IN ('. $placeholders .')', array_merge(array($menu_name), $args, $args));
|
||||
while ($item = db_fetch_array($result)) {
|
||||
$args[] = $item['mlid'];
|
||||
}
|
||||
|
@ -732,15 +736,12 @@ function menu_tree_page_data($menu_name = 'navigation') {
|
|||
}
|
||||
// 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. We need to select links that are visible or hidden
|
||||
// (ml.hidden >= 0), but not callbacks (ml.hidden < 0), so that we can
|
||||
// later exclude all the children of a hidden item.
|
||||
// No need to order by p6 - there is a sort by weight later.
|
||||
// link.
|
||||
$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.*
|
||||
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 .") AND ml.hidden >= 0
|
||||
ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC", $args), $parents);
|
||||
WHERE ml.menu_name = '%s' AND ml.plid IN (". $placeholders .")
|
||||
ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", $args), $parents);
|
||||
$data['node_links'] = array();
|
||||
menu_tree_collect_node_links($data['tree'], $data['node_links']);
|
||||
// Cache the data.
|
||||
|
@ -778,37 +779,32 @@ function menu_tree_collect_node_links(&$tree, &$node_links) {
|
|||
/**
|
||||
* Check access and perform other dynamic operations for each link in the tree.
|
||||
*/
|
||||
function menu_tree_check_access(&$tree, $node_links = array(), $show_hidden = FALSE) {
|
||||
function menu_tree_check_access(&$tree, $node_links = array()) {
|
||||
|
||||
if ($node_links) {
|
||||
// Use db_rewrite_sql to evaluate view access without loading each full node.
|
||||
$nids = array_keys($node_links);
|
||||
$placeholders = '%d' . str_repeat(', %d', count($nids) - 1);
|
||||
$placeholders = '%d'. str_repeat(', %d', count($nids) - 1);
|
||||
$result = db_query(db_rewrite_sql("SELECT n.nid FROM {node} n WHERE n.nid IN (". $placeholders .")"), $nids);
|
||||
while ($node = db_fetch_array($result)) {
|
||||
$node_links[$node['nid']]['access'] = TRUE;
|
||||
}
|
||||
}
|
||||
_menu_tree_check_access($tree, $show_hidden);
|
||||
_menu_tree_check_access($tree);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive helper function for menu_tree_check_access()
|
||||
*/
|
||||
function _menu_tree_check_access(&$tree, $show_hidden) {
|
||||
function _menu_tree_check_access(&$tree) {
|
||||
$new_tree = array();
|
||||
foreach ($tree as $key => $v) {
|
||||
$item = &$tree[$key]['link'];
|
||||
if (!$item['hidden'] || $show_hidden) {
|
||||
_menu_link_translate($item);
|
||||
}
|
||||
else {
|
||||
$item['access'] = FALSE;
|
||||
}
|
||||
_menu_link_translate($item);
|
||||
if ($item['access']) {
|
||||
if ($tree[$key]['below']) {
|
||||
_menu_tree_check_access($tree[$key]['below'], $show_hidden);
|
||||
_menu_tree_check_access($tree[$key]['below']);
|
||||
}
|
||||
// The weights are made a uniform 5 digits by adding 50000 as an offset.
|
||||
// After _menu_link_translate(), $item['title'] has the localized link title.
|
||||
|
@ -877,7 +873,7 @@ function _menu_tree_data($result, $parents, $depth, $previous_element = '') {
|
|||
// Only the first time.
|
||||
$tree[$index] = array(
|
||||
'link' => $previous_element,
|
||||
'below' => '',
|
||||
'below' => FALSE,
|
||||
);
|
||||
}
|
||||
// This will be the link to be output in the next iteration.
|
||||
|
@ -893,7 +889,7 @@ function _menu_tree_data($result, $parents, $depth, $previous_element = '') {
|
|||
// We have one more link dangling.
|
||||
$tree[$previous_element['mlid']] = array(
|
||||
'link' => $previous_element,
|
||||
'below' => '',
|
||||
'below' => FALSE,
|
||||
);
|
||||
}
|
||||
return array($remnant, $tree);
|
||||
|
@ -995,10 +991,12 @@ function menu_primary_links() {
|
|||
$tree = menu_tree_page_data('primary-links');
|
||||
$links = array();
|
||||
foreach ($tree as $item) {
|
||||
$l = $item['link']['options'];
|
||||
$l['href'] = $item['link']['href'];
|
||||
$l['title'] = $item['link']['title'];
|
||||
$links[] = $l;
|
||||
if (!$item['link']['hidden']) {
|
||||
$l = $item['link']['options'];
|
||||
$l['href'] = $item['link']['href'];
|
||||
$l['title'] = $item['link']['title'];
|
||||
$links[] = $l;
|
||||
}
|
||||
}
|
||||
return $links;
|
||||
}
|
||||
|
@ -1010,10 +1008,12 @@ function menu_secondary_links() {
|
|||
$tree = menu_tree_page_data('secondary-links');
|
||||
$links = array();
|
||||
foreach ($tree as $item) {
|
||||
$l = $item['link']['options'];
|
||||
$l['href'] = $item['link']['href'];
|
||||
$l['title'] = $item['link']['title'];
|
||||
$links[] = $l;
|
||||
if (!$item['link']['hidden']) {
|
||||
$l = $item['link']['options'];
|
||||
$l['href'] = $item['link']['href'];
|
||||
$l['title'] = $item['link']['title'];
|
||||
$links[] = $l;
|
||||
}
|
||||
}
|
||||
return $links;
|
||||
}
|
||||
|
@ -1031,10 +1031,12 @@ function menu_secondary_links() {
|
|||
* a parent tab, if the current page is a default local task.
|
||||
*/
|
||||
function menu_local_tasks($level = 0, $return_root = FALSE) {
|
||||
static $tabs = array();
|
||||
static $tabs;
|
||||
static $root_path;
|
||||
|
||||
if (empty($tabs)) {
|
||||
if (!isset($tabs)) {
|
||||
$tabs = array();
|
||||
|
||||
$router_item = menu_get_item();
|
||||
if (!$router_item || !$router_item['access']) {
|
||||
return '';
|
||||
|
@ -1461,10 +1463,8 @@ function _menu_delete_item($item) {
|
|||
}
|
||||
db_query('DELETE FROM {menu_links} WHERE mlid = %d', $item['mlid']);
|
||||
|
||||
|
||||
// Update the has_children status of the parent.
|
||||
$children = (bool)db_result(db_query("SELECT COUNT(*) FROM {menu_links} WHERE plid = %d AND hidden = 0", $item['plid']));
|
||||
db_query("UPDATE {menu_links} SET has_children = %d WHERE mlid = %d", $children, $item['plid']);
|
||||
_menu_update_parental_status($item);
|
||||
|
||||
menu_cache_clear($item['menu_name']);
|
||||
}
|
||||
|
@ -1549,7 +1549,9 @@ function menu_link_save(&$item) {
|
|||
|
||||
if (!$item['plid']) {
|
||||
$item['p1'] = $item['mlid'];
|
||||
$item['p2'] = $item['p3'] = $item['p4'] = $item['p5'] = $item['p6'] = 0;
|
||||
for ($i = 2; $i <= MENU_MAX_DEPTH; $i++) {
|
||||
$item["p$i"] = 0;
|
||||
}
|
||||
$item['depth'] = 1;
|
||||
}
|
||||
else {
|
||||
|
@ -1593,18 +1595,15 @@ function menu_link_save(&$item) {
|
|||
db_query("UPDATE {menu_links} SET menu_name = '%s', plid = %d, link_path = '%s',
|
||||
router_path = '%s', hidden = %d, external = %d, has_children = %d,
|
||||
expanded = %d, weight = %d, depth = %d,
|
||||
p1 = %d, p2 = %d, p3 = %d, p4 = %d, p5 = %d, p6 = %d,
|
||||
p1 = %d, p2 = %d, p3 = %d, p4 = %d, p5 = %d, p6 = %d, p7 = %d, p8 = %d, p9 = %d,
|
||||
module = '%s', link_title = '%s', options = '%s', customized = %d WHERE mlid = %d",
|
||||
$item['menu_name'], $item['plid'], $item['link_path'],
|
||||
$item['router_path'], $item['hidden'], $item['_external'], $item['has_children'],
|
||||
$item['expanded'], $item['weight'], $item['depth'],
|
||||
$item['p1'], $item['p2'], $item['p3'], $item['p4'], $item['p5'], $item['p6'],
|
||||
$item['p1'], $item['p2'], $item['p3'], $item['p4'], $item['p5'], $item['p6'], $item['p7'], $item['p8'], $item['p9'],
|
||||
$item['module'], $item['link_title'], serialize($item['options']), $item['customized'], $item['mlid']);
|
||||
// Check the has_children status of the parent.
|
||||
if ($item['plid']) {
|
||||
$parent_has_children = (bool)db_result(db_query("SELECT COUNT(*) FROM {menu_links} WHERE plid = %d AND hidden = 0", $item['plid']));
|
||||
db_query("UPDATE {menu_links} SET has_children = %d WHERE mlid = %d", $parent_has_children, $item['plid']);
|
||||
}
|
||||
_menu_update_parental_status($item);
|
||||
menu_cache_clear($menu_name);
|
||||
if ($existing_item && $menu_name != $existing_item['menu_name']) {
|
||||
menu_cache_clear($existing_item['menu_name']);
|
||||
|
@ -1688,7 +1687,8 @@ function _menu_link_move_children($item, $existing_item) {
|
|||
$args[] = $shift;
|
||||
$set[] = 'depth = depth + %d';
|
||||
}
|
||||
|
||||
$where[] = "menu_name = '%s'";
|
||||
$args[] = $existing_item['menu_name'];
|
||||
$p = 'p1';
|
||||
for ($i = 1; $i <= MENU_MAX_DEPTH && $existing_item[$p]; $p = 'p'. ++$i) {
|
||||
$where[] = "$p = %d";
|
||||
|
@ -1696,15 +1696,26 @@ function _menu_link_move_children($item, $existing_item) {
|
|||
}
|
||||
|
||||
db_query("UPDATE {menu_links} SET ". implode(', ', $set) ." WHERE ". implode(' AND ', $where), $args);
|
||||
// Check the has_children status of the parent, while excluding this item.
|
||||
_menu_update_parental_status($existing_item, TRUE);
|
||||
}
|
||||
|
||||
if ($existing_item['plid']) {
|
||||
$parent_has_children = (bool)db_result(db_query("SELECT COUNT(*) FROM {menu_links} WHERE plid = %d AND hidden = 0 AND mlid != %d", $existing_item['plid'], $existing_item['mlid']));
|
||||
db_query("UPDATE {menu_links} SET has_children = %d WHERE mlid = %d", $parent_has_children, $existing_item['plid']);
|
||||
/**
|
||||
* Check and update the has_children status for the parent of a link.
|
||||
*/
|
||||
function _menu_update_parental_status($item, $exclude = FALSE) {
|
||||
// If plid == 0, there is nothing to update.
|
||||
if ($item['plid']) {
|
||||
// We may want to exclude the passed link as a possible child.
|
||||
$where = $exclude ? " AND mlid != %d" : '';
|
||||
// Check if at least one visible child exists in the table.
|
||||
$parent_has_children = (bool)db_result(db_query_range("SELECT mlid FROM {menu_links} WHERE menu_name = '%s' AND plid = %d AND hidden = 0". $where, $item['menu_name'], $item['plid'], $item['mlid'], 0, 1));
|
||||
db_query("UPDATE {menu_links} SET has_children = %d WHERE mlid = %d", $parent_has_children, $item['plid']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that sets the p1..p6 values for a menu link being saved.
|
||||
* Helper function that sets the p1..p9 values for a menu link being saved.
|
||||
*/
|
||||
function _menu_link_parents_set(&$item, $parent) {
|
||||
$i = 1;
|
||||
|
@ -1713,7 +1724,7 @@ function _menu_link_parents_set(&$item, $parent) {
|
|||
$item[$p] = $parent[$p];
|
||||
}
|
||||
$p = 'p'. $i++;
|
||||
// The parent (p1 - p6) corresponding to the depth always equals the mlid.
|
||||
// The parent (p1 - p9) corresponding to the depth always equals the mlid.
|
||||
$item[$p] = $item['mlid'];
|
||||
while ($i <= MENU_MAX_DEPTH) {
|
||||
$p = 'p'. $i++;
|
||||
|
@ -1773,6 +1784,7 @@ function _menu_router_build($callbacks) {
|
|||
// If there is no %, it fits maximally.
|
||||
$fit = (1 << $number_parts) - 1;
|
||||
}
|
||||
$masks[$fit] = 1;
|
||||
$item['load_functions'] = empty($load_functions) ? '' : serialize($load_functions);
|
||||
$item['to_arg_functions'] = empty($to_arg_functions) ? '' : serialize($to_arg_functions);
|
||||
$item += array(
|
||||
|
@ -1895,6 +1907,10 @@ function _menu_router_build($callbacks) {
|
|||
$item['title'], $item['title callback'], serialize($item['title arguments']),
|
||||
$item['type'], $item['block callback'], $item['description'], $item['position'], $item['weight'], $item['include file']);
|
||||
}
|
||||
// Sort the masks so they are in order of descending fit, and store them.
|
||||
$masks = array_keys($masks);
|
||||
rsort($masks);
|
||||
variable_set('menu_masks', $masks);
|
||||
return $menu;
|
||||
}
|
||||
|
||||
|
|
|
@ -620,7 +620,7 @@ function book_outline_form_submit($form, &$form_state) {
|
|||
}
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('There was an error adding the post to the book.'));
|
||||
drupal_set_message(t('There was an error adding the post to the book.'), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1451,8 +1451,9 @@ function book_menu_subtree_data($item) {
|
|||
$data = $cache->data;
|
||||
}
|
||||
else {
|
||||
$match = array("menu_name = '%s'");
|
||||
$args = array($item['menu_name']);
|
||||
$i = 1;
|
||||
$match = array();
|
||||
while ($i <= MENU_MAX_DEPTH && $item["p$i"]) {
|
||||
$match[] = "p$i = %d";
|
||||
$args[] = $item["p$i"];
|
||||
|
@ -1460,10 +1461,10 @@ function book_menu_subtree_data($item) {
|
|||
}
|
||||
$sql = "
|
||||
SELECT b.*, 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.*
|
||||
FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path
|
||||
FROM {menu_links} ml INNER JOIN {menu_router} m ON m.path = ml.router_path
|
||||
INNER JOIN {book} b ON ml.mlid = b.mlid
|
||||
WHERE ml.hidden >= 0 AND ". implode(' AND ', $match) ."
|
||||
ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC";
|
||||
WHERE ". implode(' AND ', $match) ."
|
||||
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(db_query($sql, $args), array(), $item['depth']);
|
||||
$data['node_links'] = array();
|
||||
|
|
|
@ -70,6 +70,8 @@ function menu_menu() {
|
|||
'title' => 'Customize menu',
|
||||
'page callback' => 'menu_overview',
|
||||
'page arguments' => array(3),
|
||||
'title callback' => 'menu_overview_title',
|
||||
'title arguments' => array(3),
|
||||
'access arguments' => array('administer menu'),
|
||||
'type' => MENU_CALLBACK);
|
||||
$items['admin/build/menu-customize/%menu/list'] = array(
|
||||
|
@ -141,6 +143,13 @@ function menu_enable() {
|
|||
menu_cache_clear_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Title callback for the menu overview page and links.
|
||||
*/
|
||||
function menu_overview_title($menu) {
|
||||
return t('!menu_title (overview)', array('!menu_title' => $menu['title']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the data for a single custom menu.
|
||||
*/
|
||||
|
@ -171,14 +180,14 @@ function menu_overview($menu) {
|
|||
$sql ="
|
||||
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.*
|
||||
FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path
|
||||
WHERE ml.menu_name = '%s' AND ml.hidden >= 0
|
||||
ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC";
|
||||
$sql_count = "SELECT COUNT(*) FROM {menu_links} ml WHERE menu_name = '%s' AND hidden >= 0";
|
||||
WHERE ml.menu_name = '%s'
|
||||
ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC";
|
||||
$sql_count = "SELECT COUNT(*) FROM {menu_links} ml WHERE menu_name = '%s'";
|
||||
$result = pager_query($sql, 200, 0, $sql_count, $menu['menu_name']);
|
||||
$tree = menu_tree_data($result);
|
||||
$node_links = array();
|
||||
menu_tree_collect_node_links($tree, $node_links);
|
||||
menu_tree_check_access($tree, $node_links, TRUE);
|
||||
menu_tree_check_access($tree, $node_links);
|
||||
$rows = _menu_overview_tree($tree);
|
||||
$output = theme('table', $header, $rows);
|
||||
$output .= theme('pager', NULL, 200, 0);
|
||||
|
@ -192,9 +201,11 @@ function _menu_overview_tree($tree) {
|
|||
static $rows = array();
|
||||
foreach ($tree as $data) {
|
||||
$title = '';
|
||||
if ($item = $data['link']) {
|
||||
$item = $data['link'];
|
||||
// Don't show callbacks; these have $item['hidden'] < 0.
|
||||
if ($item && $item['hidden'] >= 0) {
|
||||
$title = str_repeat(' ', $item['depth'] - 1) . ($item['depth'] > 1 ? '- ' : '');
|
||||
$title .= l($item['link_title'], $item['href'], $item['options']);
|
||||
$title .= l($item['title'], $item['href'], $item['options']);
|
||||
// Populate the operations field.
|
||||
$operations = array();
|
||||
// Set the edit column.
|
||||
|
@ -360,7 +371,9 @@ function menu_item_delete_submit($form, &$form_state) {
|
|||
function menu_edit_item_submit($form, &$form_state) {
|
||||
$form_state['values']['options']['attributes']['title'] = $form_state['values']['description'];
|
||||
list($form_state['values']['menu_name'], $form_state['values']['plid']) = explode(':', $form_state['values']['parent']);
|
||||
menu_link_save($form_state['values']);
|
||||
if (!menu_link_save($form_state['values'])) {
|
||||
drupal_set_message(t('There was an error saving the menu link.'), 'error');
|
||||
}
|
||||
$form_state['redirect'] = 'admin/build/menu-customize/'. $form_state['values']['menu_name'];
|
||||
}
|
||||
|
||||
|
@ -379,7 +392,7 @@ function menu_edit_item_submit($form, &$form_state) {
|
|||
function menu_parent_options($menus, $item) {
|
||||
|
||||
foreach ($menus as $menu_name => $title) {
|
||||
$tree = menu_tree_all_data($menu_name, NULL, TRUE);
|
||||
$tree = menu_tree_all_data($menu_name, NULL);
|
||||
$options[$menu_name .':0'] = '<'. $title .'>';
|
||||
_menu_parents_recurse($tree, $menu_name, '--', $options, $item['mlid']);
|
||||
}
|
||||
|
@ -391,14 +404,14 @@ function menu_parent_options($menus, $item) {
|
|||
*/
|
||||
function _menu_parents_recurse($tree, $menu_name, $indent, &$options, $exclude) {
|
||||
foreach ($tree as $data) {
|
||||
if ($data['link']['mlid'] != $exclude) {
|
||||
if ($data['link']['mlid'] != $exclude && $data['link']['hidden'] >= 0) {
|
||||
$title = $indent .' '. truncate_utf8($data['link']['title'], 30, TRUE, FALSE);
|
||||
if ($data['link']['hidden']) {
|
||||
$title .= ' ('. t('disabled') .')';
|
||||
}
|
||||
$options[$menu_name .':'. $data['link']['mlid']] = $title;
|
||||
if ($data['below'] && $data['link']['depth'] < MENU_MAX_DEPTH - 1) {
|
||||
_menu_parents_recurse($data['below'], $menu_name, $indent .'--', $options, $exclude);
|
||||
_menu_parents_recurse($data['below'], $menu_name, $indent .'--', $options, $exclude);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -500,7 +513,7 @@ function menu_delete_menu_confirm_submit($form, &$form_state) {
|
|||
// Delete all links to the overview page for this menu.
|
||||
$result = db_query("SELECT mlid FROM {menu_links} ml WHERE ml.link_path = '%s'", 'admin/build/menu-customize/'. $menu['menu_name']);
|
||||
while ($m = db_fetch_array($result)) {
|
||||
menu_link_delete($m['mlid']);
|
||||
menu_link_delete($m['mlid']);
|
||||
}
|
||||
// Delete all the links in the menu and the menu from the list of custom menus.
|
||||
db_query("DELETE FROM {menu_links} WHERE menu_name = '%s'", $menu['menu_name']);
|
||||
|
@ -527,7 +540,7 @@ function menu_edit_menu_validate($form, &$form_state) {
|
|||
// We will add 'menu-' to the menu name to help avoid name-space conflicts.
|
||||
$item['menu_name'] = 'menu-'. $item['menu_name'];
|
||||
if (db_result(db_query("SELECT menu_name FROM {menu_custom} WHERE menu_name = '%s'", $item['menu_name'])) ||
|
||||
db_result(db_query_range("SELECT menu_name FROM {menu_links} WHERE menu_name = '%s'", $item['menu_name'], 0, 1))) {
|
||||
db_result(db_query_range("SELECT menu_name FROM {menu_links} WHERE menu_name = '%s'", $item['menu_name'], 0, 1))) {
|
||||
form_set_error('menu_name', t('Menu already exists'));
|
||||
}
|
||||
}
|
||||
|
@ -663,7 +676,9 @@ function menu_nodeapi(&$node, $op) {
|
|||
if (!$item['customized']) {
|
||||
$item['options']['attributes']['title'] = trim($node->title);
|
||||
}
|
||||
menu_link_save($item);
|
||||
if (!menu_link_save($item)) {
|
||||
drupal_set_message(t('There was an error saving the menu link.'), 'error');
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -3333,6 +3333,9 @@ function system_update_6020() {
|
|||
'plid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
|
||||
'link_path' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
|
||||
'router_path' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
|
||||
'link_title' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
|
||||
'options' => array('type' => 'text', 'not null' => FALSE),
|
||||
'module' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => 'system'),
|
||||
'hidden' => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
|
||||
'external' => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
|
||||
'has_children' => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
|
||||
|
@ -3346,16 +3349,15 @@ function system_update_6020() {
|
|||
'p4' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
|
||||
'p5' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
|
||||
'p6' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
|
||||
'module' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => 'system'),
|
||||
'link_title' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
|
||||
'options' => array('type' => 'text', 'not null' => FALSE)
|
||||
'p7' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
|
||||
'p8' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
|
||||
'p9' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
|
||||
),
|
||||
'indexes' => array(
|
||||
'expanded_children' => array('expanded', 'has_children'),
|
||||
'menu_name_path' => array('menu_name', 'link_path'),
|
||||
'plid'=> array('plid'),
|
||||
'parents' => array('p1', 'p2', 'p3', 'p4', 'p5'),
|
||||
'router_path' => array('router_path'),
|
||||
'path_menu' => array(array('link_path', 128), 'menu_name'),
|
||||
'menu_plid_expand_child' => array('menu_name', 'plid', 'expanded', 'has_children'),
|
||||
'menu_parents' => array('menu_name', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8', 'p9'),
|
||||
'router_path' => array(array('router_path', 128)),
|
||||
),
|
||||
'primary key' => array('mlid'),
|
||||
);
|
||||
|
|
|
@ -104,6 +104,9 @@ function system_schema() {
|
|||
'plid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
|
||||
'link_path' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
|
||||
'router_path' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
|
||||
'link_title' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
|
||||
'options' => array('type' => 'text', 'not null' => FALSE),
|
||||
'module' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => 'system'),
|
||||
'hidden' => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
|
||||
'external' => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
|
||||
'has_children' => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
|
||||
|
@ -117,16 +120,15 @@ function system_schema() {
|
|||
'p4' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
|
||||
'p5' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
|
||||
'p6' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
|
||||
'module' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => 'system'),
|
||||
'link_title' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
|
||||
'options' => array('type' => 'text', 'not null' => FALSE)
|
||||
'p7' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
|
||||
'p8' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
|
||||
'p9' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
|
||||
),
|
||||
'indexes' => array(
|
||||
'expanded_children' => array('expanded', 'has_children'),
|
||||
'menu_name_path' => array('menu_name', 'link_path'),
|
||||
'plid'=> array('plid'),
|
||||
'parents' => array('p1', 'p2', 'p3', 'p4', 'p5'),
|
||||
'router_path' => array('router_path'),
|
||||
'path_menu' => array(array('link_path', 128), 'menu_name'),
|
||||
'menu_plid_expand_child' => array('menu_name', 'plid', 'expanded', 'has_children'),
|
||||
'menu_parents' => array('menu_name', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8', 'p9'),
|
||||
'router_path' => array(array('router_path', 128)),
|
||||
),
|
||||
'primary key' => array('mlid'),
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue