/**
* Handles dynamic path translation and menu access control.
*
* When a user arrives on a page such as node/5, this function determines
* what "5" corresponds to, by inspecting the page's menu path definition,
* node/[node_form_arg]. This will call node_form_arg(MENU_HANDLE_REQUEST, 5)
* and get back the correspodning node object.
*
* It also works in reverse, to allow the display of tabs and menu items which
* contain these dynamic arguments, translating node/[node_form_arg] to node/5.
*
* @param $item
* A menu item object
* @param $map
* An array of path indexes => path arguments. (ex: array(tracker, 5))
* @param $direction
* The direction in which the menu item is coming; either:
* - MENU_INCOMING: The path that is currently being loaded.
* - MENU_OUTGOING: A path that needs to be shown to the user.
*/
function _menu_access($item, $map, $direction = MENU_INCOMING) {
$path = '';
// Check if there are dynamic arguments in the path that need to be calculated.
if ($item->replacements) {
$replacements = unserialize($item->replacements);
$path_map = ($direction == MENU_INCOMING) ? $map : explode('/', $item->path);
foreach ($replacements as $index => $function) {
// Translate place-holders into real values; for example, translate [user_current] to 5.
if ($direction == MENU_OUTGOING) {
if ($return = $function(MENU_OUTGOING, !empty($map[$index]) ? $map[$index] : '')) {
$path_map[$index] = $return;
}
}
// Map replacement value.
$return = $function(MENU_INCOMING, !empty($path_map[$index]) ? $path_map[$index] : '');
// If callback returned an error, trigger 404.
if ($return === FALSE) {
return array(FALSE, FALSE, '');
}
$map[$index] = $return;
}
// Re-join the path with the new replacement value.
if ($direction == MENU_OUTGOING ) {
$path = implode('/', $path_map);
}
}
// Determine access callback, which will decide whether or not the current user has
// access to this path.
$callback = $item->access_callback;
// Check for a blanket TRUE or FALSE.
if (is_numeric($callback)) {
return array($callback, $map, $path);
}
$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);
}
return array(call_user_func_array($callback, $arguments), $map, $path);
}