- Patch #125763 by chx: menu system fixes/enhancements.
parent
b1d492ee98
commit
0cb5532a23
|
@ -385,7 +385,7 @@ function _menu_translate($item, $map, $operation = MENU_HANDLE_REQUEST) {
|
|||
$map[$index] = $return;
|
||||
}
|
||||
}
|
||||
if ($operation != MENU_HANDLE_REQUEST) {
|
||||
if ($operation == MENU_RENDER_LINK) {
|
||||
// Re-join the path with the new replacement value.
|
||||
$path = implode('/', $path_map);
|
||||
}
|
||||
|
@ -393,39 +393,46 @@ function _menu_translate($item, $map, $operation = MENU_HANDLE_REQUEST) {
|
|||
else {
|
||||
$path = $item->path;
|
||||
}
|
||||
|
||||
// Determine access callback, which will decide whether or not the current user has
|
||||
// access to this path.
|
||||
$callback = $item->access_callback;
|
||||
// Check for a TRUE or FALSE value.
|
||||
if (is_numeric($callback)) {
|
||||
return array($callback, $map, $path);
|
||||
$access = $callback;
|
||||
}
|
||||
$arguments = menu_unserialize($item->access_arguments, $map);
|
||||
// As call_user_func_array is quite slow and user_access is a very common
|
||||
// callback, it is worth making a special case for it.
|
||||
if ($callback == 'user_access') {
|
||||
$access = (count($arguments) == 1) ? user_access($arguments[0]) : user_access($arguments[0], $arguments[1]);
|
||||
return array($access, $map, $path);
|
||||
else {
|
||||
$arguments = menu_unserialize($item->access_arguments, $map);
|
||||
// As call_user_func_array is quite slow and user_access is a very common
|
||||
// callback, it is worth making a special case for it.
|
||||
if ($callback == 'user_access') {
|
||||
$access = (count($arguments) == 1) ? user_access($arguments[0]) : user_access($arguments[0], $arguments[1]);
|
||||
}
|
||||
else {
|
||||
$access = call_user_func_array($callback, $arguments);
|
||||
}
|
||||
}
|
||||
return array(call_user_func_array($callback, $arguments), $map, $path);
|
||||
return array($access, $map, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a rendered menu tree.
|
||||
*/
|
||||
function menu_tree() {
|
||||
global $user;
|
||||
if ($item = menu_get_item()) {
|
||||
list(, $menu) = _menu_tree(db_query('SELECT * FROM {menu} WHERE pid IN ('. $item->parents .') AND visible = 1 ORDER BY vancode'));
|
||||
list(, $menu) = _menu_tree(db_query('SELECT * FROM {menu} WHERE pid IN ('. $item->parents .') AND visible = 1 ORDER BY mleft'));
|
||||
return $menu;
|
||||
}
|
||||
}
|
||||
|
||||
function _menu_tree($result = NULL, $depth = 0, $link = array('link' => '', 'has_children' => FALSE)) {
|
||||
static $original_map;
|
||||
static $map;
|
||||
$remnant = array('link' => '', 'has_children' => FALSE);
|
||||
$tree = '';
|
||||
$map = arg(NULL);
|
||||
if (!isset($map)) {
|
||||
$map = arg(NULL);
|
||||
}
|
||||
$old_type = -1;
|
||||
while ($item = db_fetch_object($result)) {
|
||||
list($access, , $path) = _menu_translate($item, $map, MENU_RENDER_LINK);
|
||||
if (!$access) {
|
||||
|
@ -434,18 +441,27 @@ function _menu_tree($result = NULL, $depth = 0, $link = array('link' => '', 'has
|
|||
$menu_link = array('link' => l($item->title, $path), 'has_children' => $item->has_children);
|
||||
if ($item->depth > $depth) {
|
||||
list($remnant, $menu) = _menu_tree($result, $item->depth, $menu_link);
|
||||
$tree .= theme('menu_tree', $link, $menu);
|
||||
if ($menu) {
|
||||
$tree .= theme('menu_tree', $link, $menu);
|
||||
}
|
||||
else {
|
||||
$tree .= theme('menu_link', $link);
|
||||
}
|
||||
$link = $remnant;
|
||||
$remnant = array('link' => '', 'has_children' => FALSE);
|
||||
}
|
||||
elseif ($item->depth == $depth) {
|
||||
$tree .= theme('menu_link', $link);
|
||||
if ($link['link'] && !($old_type & MENU_VISIBLE_IF_HAS_CHILDREN)) {
|
||||
$tree .= theme('menu_link', $link);
|
||||
}
|
||||
$link = $menu_link;
|
||||
}
|
||||
// it's the end of a submenu
|
||||
else {
|
||||
$remnant = $menu_link;
|
||||
break;
|
||||
}
|
||||
$old_type = $item->type;
|
||||
}
|
||||
if ($link['link']) {
|
||||
$tree .= theme('menu_link', $link);
|
||||
|
@ -506,7 +522,7 @@ function menu_get_active_help() {
|
|||
* Populate the database representation of the menu.
|
||||
*/
|
||||
function menu_rebuild() {
|
||||
$next = array();
|
||||
// TODO: split menu and menu links storage.
|
||||
db_query('DELETE FROM {menu}');
|
||||
$menu = module_invoke_all('menu');
|
||||
foreach (module_implements('menu_alter') as $module) {
|
||||
|
@ -532,7 +548,6 @@ function menu_rebuild() {
|
|||
if (empty($matches[1])) {
|
||||
$match = TRUE;
|
||||
$load_functions[$k] = NULL;
|
||||
$to_arg_functions[$k] = NULL;
|
||||
}
|
||||
else {
|
||||
if (function_exists($matches[1] .'_to_arg')) {
|
||||
|
@ -571,6 +586,7 @@ function menu_rebuild() {
|
|||
'_parts' => $parts,
|
||||
'_fit' => $fit,
|
||||
'_mid' => $mid++,
|
||||
'_children' => array(),
|
||||
);
|
||||
$item += array(
|
||||
'_visible' => (bool)($item['type'] & MENU_VISIBLE_IN_TREE),
|
||||
|
@ -583,37 +599,34 @@ function menu_rebuild() {
|
|||
else {
|
||||
$new_path = $path;
|
||||
}
|
||||
$menu_path_map[$path] = $new_path;
|
||||
$menu[$new_path] = $item;
|
||||
}
|
||||
// Second pass: find visible parents and prepare for sorting.
|
||||
$menu_path_map[''] = '';
|
||||
// Second pass: prepare for sorting and find parents.
|
||||
foreach ($menu as $path => $item) {
|
||||
$item = &$menu[$path];
|
||||
$number_parts = $item['_number_parts'];
|
||||
$parents = array($item['_mid']);
|
||||
if ($item['_visible'] && isset($item['parent'])) {
|
||||
$parent_parts = explode('/', $item['parent'], 6);
|
||||
if (isset($item['parent'])) {
|
||||
$parent_parts = explode('/', $menu_path_map[$item['parent']], 6);
|
||||
$slashes = count($parent_parts) - 1;
|
||||
}
|
||||
else {
|
||||
$parent_parts = $item['_parts'];
|
||||
$slashes = $number_parts -1;
|
||||
$slashes = $number_parts - 1;
|
||||
}
|
||||
$depth = 1;
|
||||
$parents = array($item['_mid']);
|
||||
for ($i = $slashes; $i; $i--) {
|
||||
$parent_path = implode('/', array_slice($parent_parts, 0, $i));
|
||||
// We need to calculate depth to be able to sort. depth needs visibility.
|
||||
if (isset($menu[$parent_path])) {
|
||||
$parent = &$menu[$parent_path];
|
||||
if ($item['_visible'] && $parent['_visible']) {
|
||||
$parent['_has_children'] = 1;
|
||||
$depth++;
|
||||
$parents[] = $parent['_mid'];
|
||||
if (!isset($item['_pid'])) {
|
||||
$item['_pid'] = $parent['_mid'];
|
||||
$item['_visible_parent_path'] = $parent_path;
|
||||
}
|
||||
if (isset($menu[$parent_path]) && $menu[$parent_path]['_visible']) {
|
||||
$parent = $menu[$parent_path];
|
||||
$parents[] = $parent['_mid'];
|
||||
$depth++;
|
||||
if (!isset($item['_pid'])) {
|
||||
$item['_pid'] = $parent['_mid'];
|
||||
$item['_visible_parent_path'] = $parent_path;
|
||||
}
|
||||
unset($parent);
|
||||
}
|
||||
}
|
||||
$parents[] = 0;
|
||||
|
@ -621,15 +634,24 @@ function menu_rebuild() {
|
|||
// Store variables and set defaults.
|
||||
$item += array(
|
||||
'_pid' => 0,
|
||||
'_depth' => $item['_visible'] ? $depth : $number_parts,
|
||||
'_depth' => ($item['_visible'] ? $depth : $number_parts),
|
||||
'_parents' => $parents,
|
||||
'_has_children' => 0,
|
||||
'_parent_parts' => $parent_parts,
|
||||
'_slashes' => $slashes,
|
||||
);
|
||||
$sort[$path] = $item['_depth'] . sprintf('%05d', $item['weight']) . $item['title'];
|
||||
unset($item);
|
||||
}
|
||||
array_multisort($sort, $menu);
|
||||
// Third pass: calculate ancestors, vancode and store into the database.
|
||||
// We are now sorted, so let's build the tree.
|
||||
$children = array();
|
||||
foreach ($menu as $path => $item) {
|
||||
if ($item['_pid']) {
|
||||
$menu[$item['_visible_parent_path']]['_children'][] = $path;
|
||||
}
|
||||
}
|
||||
menu_renumber($menu);
|
||||
// Apply inheritance rules.
|
||||
foreach ($menu as $path => $item) {
|
||||
$item = &$menu[$path];
|
||||
for ($i = $item['_number_parts'] - 1; $i; $i--) {
|
||||
|
@ -650,28 +672,17 @@ function menu_rebuild() {
|
|||
}
|
||||
}
|
||||
if (!isset($item['access callback'])) {
|
||||
$menu[$path]['access callback'] = isset($item['access arguments']) ? 'user_access' : 0;
|
||||
$item['access callback'] = isset($item['access arguments']) ? 'user_access' : 0;
|
||||
}
|
||||
if (is_bool($item['access callback'])) {
|
||||
$item['access callback'] = intval($item['access callback']);
|
||||
}
|
||||
if ($item['_visible']) {
|
||||
$prefix = isset($item['_visible_parent_path']) ? $menu[$item['_visible_parent_path']]['_prefix'] : '';
|
||||
if (!isset($next[$prefix])) {
|
||||
$next[$prefix] = 0;
|
||||
}
|
||||
$vancode = $prefix . int2vancode($next[$prefix]++);
|
||||
$menu[$path]['_prefix'] = $vancode .'.';
|
||||
}
|
||||
else {
|
||||
$vancode = '';
|
||||
}
|
||||
if ($item['_tab']) {
|
||||
if (!isset($item['parent'])) {
|
||||
$item['parent'] = implode('/', array_slice($item['_parts'], 0, $item['_number_parts'] - 1));
|
||||
}
|
||||
else {
|
||||
$item['_depth'] = $item['parent'] ? $menu[$item['parent']]['_depth'] + 1 : 1;
|
||||
$item['_depth'] = $item['parent'] ? $menu[$menu_path_map[$item['parent']]]['_depth'] + 1 : 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -679,32 +690,51 @@ function menu_rebuild() {
|
|||
// stored in parents, parent stores the tab parent.
|
||||
$item['parent'] = $path;
|
||||
}
|
||||
$insert_item = $item + array(
|
||||
$insert_item = $item;
|
||||
unset($item);
|
||||
$item = $insert_item + array(
|
||||
'access arguments' => array(),
|
||||
'access callback' => '',
|
||||
'page arguments' => array(),
|
||||
'page callback' => '',
|
||||
'_mleft' => 0,
|
||||
'_mright' => 0,
|
||||
);
|
||||
db_query("INSERT INTO {menu} (
|
||||
mid, pid, path, load_functions, to_arg_functions,
|
||||
access_callback, access_arguments, page_callback, page_arguments, fit,
|
||||
number_parts, vancode, visible, parents, depth, has_children, tab, title, parent, type)
|
||||
VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, '%s', %d, %d, %d, '%s', '%s', '%s')",
|
||||
$insert_item['_mid'], $insert_item['_pid'], $path,
|
||||
$insert_item['load_functions'], $insert_item['to_arg_functions'],
|
||||
$insert_item['access callback'], serialize($insert_item['access arguments']),
|
||||
$insert_item['page callback'], serialize($insert_item['page arguments']),
|
||||
$insert_item['_fit'], $insert_item['_number_parts'], $vancode .'+',
|
||||
$insert_item['_visible'], $insert_item['_parents'], $insert_item['_depth'],
|
||||
$insert_item['_has_children'], $item['_tab'], $insert_item['title'],
|
||||
$insert_item['parent'], $insert_item['type']);
|
||||
unset($item);
|
||||
number_parts, visible, parents, depth, has_children, tab, title, parent,
|
||||
type, mleft, mright)
|
||||
VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d,
|
||||
'%s', %d, %d, %d, '%s', '%s', '%s', %d, %d)",
|
||||
$item['_mid'], $item['_pid'], $path, $item['load_functions'],
|
||||
$item['to_arg_functions'], $item['access callback'],
|
||||
serialize($item['access arguments']), $item['page callback'],
|
||||
serialize($item['page arguments']), $item['_fit'],
|
||||
$item['_number_parts'], $item['_visible'], $item['_parents'],
|
||||
$item['_depth'], !empty($item['_children']), $item['_tab'],
|
||||
$item['title'], $item['parent'], $item['type'], $item['_mleft'],
|
||||
$item['_mright']);
|
||||
}
|
||||
}
|
||||
|
||||
function menu_map($arg, $function, $index, $default = FALSE) {
|
||||
$arg[$index] = is_numeric($arg[$index]) ? $function($arg[$index]) : $default;
|
||||
return $arg[$index] ? $arg : FALSE;
|
||||
function menu_renumber(&$tree) {
|
||||
foreach ($tree as $key => $element) {
|
||||
if (!isset($tree[$key]['_mleft'])) {
|
||||
_menu_renumber($tree, $key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _menu_renumber(&$tree, $key) {
|
||||
static $counter = 1;
|
||||
if (!isset($tree[$key]['_mleft'])) {
|
||||
$tree[$key]['_mleft'] = $counter++;
|
||||
foreach ($tree[$key]['_children'] as $child_key) {
|
||||
_menu_renumber($tree, $child_key);
|
||||
}
|
||||
$tree[$key]['_mright'] = $counter++;
|
||||
}
|
||||
}
|
||||
|
||||
// Placeholders.
|
||||
|
@ -741,7 +771,7 @@ function menu_local_tasks($level = 0) {
|
|||
continue;
|
||||
}
|
||||
// This loads all the tabs.
|
||||
$result = db_query("SELECT * FROM {menu} WHERE parent = '%s' AND tab = 1 ORDER BY vancode", $parent);
|
||||
$result = db_query("SELECT * FROM {menu} WHERE parent = '%s' AND tab = 1 ORDER BY mleft", $parent);
|
||||
$tabs_current = '';
|
||||
while ($item = db_fetch_object($result)) {
|
||||
// This call changes the path from for example user/% to user/123 and
|
||||
|
|
|
@ -328,8 +328,8 @@ function system_install() {
|
|||
) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
|
||||
|
||||
db_query("CREATE TABLE {menu} (
|
||||
mid int NOT NULL default '0',
|
||||
pid int NOT NULL default '0',
|
||||
mid int NOT NULL default 0,
|
||||
pid int NOT NULL default 0,
|
||||
path varchar(255) NOT NULL default '',
|
||||
load_functions varchar(255) NOT NULL default '',
|
||||
to_arg_functions varchar(255) NOT NULL default '',
|
||||
|
@ -337,19 +337,19 @@ function system_install() {
|
|||
access_arguments text,
|
||||
page_callback varchar(255) NOT NULL default '',
|
||||
page_arguments text,
|
||||
fit int NOT NULL default '0',
|
||||
number_parts int NOT NULL default '0',
|
||||
vancode varchar(255) NOT NULL default '',
|
||||
visible int NOT NULL default '0',
|
||||
fit int NOT NULL default 0,
|
||||
number_parts int NOT NULL default 0,
|
||||
mleft int NOT NULL default 0,
|
||||
mright int NOT NULL default 0,
|
||||
visible int NOT NULL default 0,
|
||||
parents varchar(255) NOT NULL default '',
|
||||
depth int NOT NULL default '0',
|
||||
has_children int NOT NULL default '0',
|
||||
depth int NOT NULL default 0,
|
||||
has_children int NOT NULL default 0,
|
||||
tab int NOT NULL default 0,
|
||||
title varchar(255) NOT NULL default '',
|
||||
parent varchar(255) NOT NULL default '',
|
||||
type int NOT NULL default 0,
|
||||
PRIMARY KEY (path),
|
||||
KEY vancode (vancode),
|
||||
KEY fit (fit),
|
||||
KEY visible (visible),
|
||||
KEY pid (pid),
|
||||
|
@ -803,8 +803,8 @@ function system_install() {
|
|||
)");
|
||||
|
||||
db_query("CREATE TABLE {menu} (
|
||||
mid int NOT NULL default '0',
|
||||
pid int NOT NULL default '0',
|
||||
mid int NOT NULL default 0,
|
||||
pid int NOT NULL default 0,
|
||||
path varchar(255) NOT NULL default '',
|
||||
load_functions varchar(255) NOT NULL default '',
|
||||
to_arg_functions varchar(255) NOT NULL default '',
|
||||
|
@ -812,13 +812,14 @@ function system_install() {
|
|||
access_arguments text,
|
||||
page_callback varchar(255) NOT NULL default '',
|
||||
page_arguments text,
|
||||
fit int NOT NULL default '0',
|
||||
number_parts int NOT NULL default '0',
|
||||
vancode varchar(255) NOT NULL default '',
|
||||
visible int NOT NULL default '0',
|
||||
fit int NOT NULL default 0,
|
||||
number_parts int NOT NULL default 0,
|
||||
mleft int NOT NULL default 0,
|
||||
mright int NOT NULL default 0,
|
||||
visible int NOT NULL default 0,
|
||||
parents varchar(255) NOT NULL default '',
|
||||
depth int NOT NULL default '0',
|
||||
has_children int NOT NULL default '0',
|
||||
depth int NOT NULL default 0,
|
||||
has_children int NOT NULL default 0,
|
||||
tab int NOT NULL default 0,
|
||||
title varchar(255) NOT NULL default '',
|
||||
parent varchar(255) NOT NULL default '',
|
||||
|
@ -826,7 +827,6 @@ function system_install() {
|
|||
PRIMARY KEY (path)
|
||||
)");
|
||||
|
||||
db_query("CREATE INDEX {menu}_vancode_idx ON {menu} (vancode)");
|
||||
db_query("CREATE INDEX {menu}_fit_idx ON {menu} (fit)");
|
||||
db_query("CREATE INDEX {menu}_visible_idx ON {menu} (visible)");
|
||||
db_query("CREATE INDEX {menu}_parent_idx ON {menu} (parent)");
|
||||
|
|
|
@ -735,6 +735,7 @@ function user_menu() {
|
|||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('user_login'),
|
||||
'access callback' => 'user_is_anonymous',
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
|
||||
$items['user/login'] = array(
|
||||
|
|
Loading…
Reference in New Issue