function _menu_router_build in Drupal 6
Same name and namespace in other branches
- 7 includes/menu.inc \_menu_router_build()
Helper function to build the router table based on the data from hook_menu.
Related topics
1 call to _menu_router_build()
- menu_router_build in includes/
menu.inc - Collect, alter and store the menu definitions.
File
- includes/
menu.inc, line 2275 - API for the Drupal menu system.
Code
function _menu_router_build($callbacks) {
// First pass: separate callbacks from paths, making paths ready for
// matching. Calculate fitness, and fill some default values.
$menu = array();
foreach ($callbacks as $path => $item) {
$load_functions = array();
$to_arg_functions = array();
$fit = 0;
$move = FALSE;
$parts = explode('/', $path, MENU_MAX_PARTS);
$number_parts = count($parts);
// We store the highest index of parts here to save some work in the fit
// calculation loop.
$slashes = $number_parts - 1;
// Extract load and to_arg functions.
foreach ($parts as $k => $part) {
$match = FALSE;
// Look for wildcards in the form allowed to be used in PHP functions,
// because we are using these to construct the load function names.
// See http://php.net/manual/en/language.functions.php for reference.
if (preg_match('/^%(|[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)$/', $part, $matches)) {
if (empty($matches[1])) {
$match = TRUE;
$load_functions[$k] = NULL;
}
else {
if (function_exists($matches[1] . '_to_arg')) {
$to_arg_functions[$k] = $matches[1] . '_to_arg';
$load_functions[$k] = NULL;
$match = TRUE;
}
if (function_exists($matches[1] . '_load')) {
$function = $matches[1] . '_load';
// Create an array of arguments that will be passed to the _load
// function when this menu path is checked, if 'load arguments'
// exists.
$load_functions[$k] = isset($item['load arguments']) ? array(
$function => $item['load arguments'],
) : $function;
$match = TRUE;
}
}
}
if ($match) {
$parts[$k] = '%';
}
else {
$fit |= 1 << $slashes - $k;
}
}
if ($fit) {
$move = TRUE;
}
else {
// 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(
'title' => '',
'weight' => 0,
'type' => MENU_NORMAL_ITEM,
'_number_parts' => $number_parts,
'_parts' => $parts,
'_fit' => $fit,
);
$item += array(
'_visible' => (bool) ($item['type'] & MENU_VISIBLE_IN_BREADCRUMB),
'_tab' => (bool) ($item['type'] & MENU_IS_LOCAL_TASK),
);
if ($move) {
$new_path = implode('/', $item['_parts']);
$menu[$new_path] = $item;
$sort[$new_path] = $number_parts;
}
else {
$menu[$path] = $item;
$sort[$path] = $number_parts;
}
}
array_multisort($sort, SORT_NUMERIC, $menu);
if (!$menu) {
// We must have a serious error - there is no data to save.
watchdog('php', 'Menu router rebuild failed - some paths may not work correctly.', array(), WATCHDOG_ERROR);
return array();
}
// Delete the existing router since we have some data to replace it.
db_query('DELETE FROM {menu_router}');
// Apply inheritance rules.
foreach ($menu as $path => $v) {
$item =& $menu[$path];
if (!$item['_tab']) {
// Non-tab items.
$item['tab_parent'] = '';
$item['tab_root'] = $path;
}
for ($i = $item['_number_parts'] - 1; $i; $i--) {
$parent_path = implode('/', array_slice($item['_parts'], 0, $i));
if (isset($menu[$parent_path])) {
$parent = $menu[$parent_path];
if (!isset($item['tab_parent'])) {
// Parent stores the parent of the path.
$item['tab_parent'] = $parent_path;
}
if (!isset($item['tab_root']) && !$parent['_tab']) {
$item['tab_root'] = $parent_path;
}
// If an access callback is not found for a default local task we use
// the callback from the parent, since we expect them to be identical.
// In all other cases, the access parameters must be specified.
if ($item['type'] == MENU_DEFAULT_LOCAL_TASK && !isset($item['access callback']) && isset($parent['access callback'])) {
$item['access callback'] = $parent['access callback'];
if (!isset($item['access arguments']) && isset($parent['access arguments'])) {
$item['access arguments'] = $parent['access arguments'];
}
}
// Same for page callbacks.
if (!isset($item['page callback']) && isset($parent['page callback'])) {
$item['page callback'] = $parent['page callback'];
if (!isset($item['page arguments']) && isset($parent['page arguments'])) {
$item['page arguments'] = $parent['page arguments'];
}
if (!isset($item['file']) && isset($parent['file'])) {
$item['file'] = $parent['file'];
}
if (!isset($item['file path']) && isset($parent['file path'])) {
$item['file path'] = $parent['file path'];
}
}
}
}
if (!isset($item['access callback']) && isset($item['access arguments'])) {
// Default callback.
$item['access callback'] = 'user_access';
}
if (!isset($item['access callback']) || empty($item['page callback'])) {
$item['access callback'] = 0;
}
if (is_bool($item['access callback'])) {
$item['access callback'] = intval($item['access callback']);
}
$item += array(
'access arguments' => array(),
'access callback' => '',
'page arguments' => array(),
'page callback' => '',
'block callback' => '',
'title arguments' => array(),
'title callback' => 't',
'description' => '',
'position' => '',
'tab_parent' => '',
'tab_root' => $path,
'path' => $path,
'file' => '',
'file path' => '',
'include file' => '',
'module' => '',
);
// Calculate out the file to be included for each callback, if any.
if ($item['file']) {
$file_path = $item['file path'] ? $item['file path'] : drupal_get_path('module', $item['module']);
$item['include file'] = $file_path . '/' . $item['file'];
}
$title_arguments = $item['title arguments'] ? serialize($item['title arguments']) : '';
db_query("INSERT INTO {menu_router}\n (path, load_functions, to_arg_functions, access_callback,\n access_arguments, page_callback, page_arguments, fit,\n number_parts, tab_parent, tab_root,\n title, title_callback, title_arguments,\n type, block_callback, description, position, weight, file)\n VALUES ('%s', '%s', '%s', '%s',\n '%s', '%s', '%s', %d,\n %d, '%s', '%s',\n '%s', '%s', '%s',\n %d, '%s', '%s', '%s', %d, '%s')", $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['tab_parent'], $item['tab_root'], $item['title'], $item['title callback'], $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;
}