00001 <?php
00002
00003
00083 define('MENU_IS_ROOT', 0x0001);
00084
00088 define('MENU_VISIBLE_IN_TREE', 0x0002);
00089
00093 define('MENU_VISIBLE_IN_BREADCRUMB', 0x0004);
00094
00098 define('MENU_LINKS_TO_PARENT', 0x0008);
00099
00103 define('MENU_MODIFIED_BY_ADMIN', 0x0020);
00104
00108 define('MENU_CREATED_BY_ADMIN', 0x0040);
00109
00113 define('MENU_IS_LOCAL_TASK', 0x0080);
00114
00133 define('MENU_NORMAL_ITEM', MENU_VISIBLE_IN_TREE | MENU_VISIBLE_IN_BREADCRUMB);
00134
00141 define('MENU_CALLBACK', MENU_VISIBLE_IN_BREADCRUMB);
00142
00151 define('MENU_SUGGESTED_ITEM', MENU_VISIBLE_IN_BREADCRUMB | 0x0010);
00152
00160 define('MENU_LOCAL_TASK', MENU_IS_LOCAL_TASK);
00161
00168 define('MENU_DEFAULT_LOCAL_TASK', MENU_IS_LOCAL_TASK | MENU_LINKS_TO_PARENT);
00169
00183 define('MENU_FOUND', 1);
00184
00188 define('MENU_NOT_FOUND', 2);
00189
00193 define('MENU_ACCESS_DENIED', 3);
00194
00198 define('MENU_SITE_OFFLINE', 4);
00199
00213 define('MENU_MAX_PARTS', 7);
00214
00215
00219 define('MENU_MAX_DEPTH', 9);
00220
00221
00253 function menu_get_ancestors($parts) {
00254 $number_parts = count($parts);
00255 $placeholders = array();
00256 $ancestors = array();
00257 $length = $number_parts - 1;
00258 $end = (1 << $number_parts) - 1;
00259 $masks = variable_get('menu_masks', array());
00260
00261 foreach ($masks as $i) {
00262 if ($i > $end) {
00263
00264 continue;
00265 }
00266 elseif ($i < (1 << $length)) {
00267
00268 --$length;
00269 }
00270 $current = '';
00271 for ($j = $length; $j >= 0; $j--) {
00272 if ($i & (1 << $j)) {
00273 $current .= $parts[$length - $j];
00274 }
00275 else {
00276 $current .= '%';
00277 }
00278 if ($j) {
00279 $current .= '/';
00280 }
00281 }
00282 $placeholders[] = "'%s'";
00283 $ancestors[] = $current;
00284 }
00285 return array($ancestors, $placeholders);
00286 }
00287
00308 function menu_unserialize($data, $map) {
00309 if ($data = unserialize($data)) {
00310 foreach ($data as $k => $v) {
00311 if (is_int($v)) {
00312 $data[$k] = isset($map[$v]) ? $map[$v] : '';
00313 }
00314 }
00315 return $data;
00316 }
00317 else {
00318 return array();
00319 }
00320 }
00321
00322
00323
00335 function menu_set_item($path, $router_item) {
00336 menu_get_item($path, $router_item);
00337 }
00338
00354 function menu_get_item($path = NULL, $router_item = NULL) {
00355 static $router_items;
00356 if (!isset($path)) {
00357 $path = $_GET['q'];
00358 }
00359 if (isset($router_item)) {
00360 $router_items[$path] = $router_item;
00361 }
00362 if (!isset($router_items[$path])) {
00363 $original_map = arg(NULL, $path);
00364 $parts = array_slice($original_map, 0, MENU_MAX_PARTS);
00365 list($ancestors, $placeholders) = menu_get_ancestors($parts);
00366
00367 if ($router_item = db_fetch_array(db_query_range('SELECT * FROM {menu_router} WHERE path IN (' . implode (',', $placeholders) . ') ORDER BY fit DESC', $ancestors, 0, 1))) {
00368 $map = _menu_translate($router_item, $original_map);
00369 if ($map === FALSE) {
00370 $router_items[$path] = FALSE;
00371 return FALSE;
00372 }
00373 if ($router_item['access']) {
00374 $router_item['map'] = $map;
00375 $router_item['page_arguments'] = array_merge(menu_unserialize($router_item['page_arguments'], $map), array_slice($map, $router_item['number_parts']));
00376 }
00377 }
00378 $router_items[$path] = $router_item;
00379 }
00380 return $router_items[$path];
00381 }
00382
00386 function menu_execute_active_handler($path = NULL) {
00387 if (_menu_site_is_offline()) {
00388 return MENU_SITE_OFFLINE;
00389 }
00390 if (variable_get('menu_rebuild_needed', FALSE)) {
00391 menu_rebuild();
00392 }
00393 if ($router_item = menu_get_item($path)) {
00394 registry_load_path_files();
00395 if ($router_item['access']) {
00396 if (drupal_function_exists($router_item['page_callback'])) {
00397 return call_user_func_array($router_item['page_callback'], $router_item['page_arguments']);
00398 }
00399 }
00400 else {
00401 return MENU_ACCESS_DENIED;
00402 }
00403 }
00404 return MENU_NOT_FOUND;
00405 }
00406
00421 function _menu_load_objects(&$item, &$map) {
00422 if ($load_functions = $item['load_functions']) {
00423
00424 if ($load_functions_unserialized = unserialize($load_functions)) {
00425 $load_functions = $load_functions_unserialized;
00426 }
00427 $path_map = $map;
00428 foreach ($load_functions as $index => $function) {
00429 if ($function) {
00430 $value = isset($path_map[$index]) ? $path_map[$index] : '';
00431 if (is_array($function)) {
00432
00433
00434
00435
00436 list($function, $args) = each($function);
00437 $load_functions[$index] = $function;
00438
00439
00440 foreach ($args as $i => $arg) {
00441 if ($arg === '%index') {
00442
00443
00444 $args[$i] = $index;
00445 }
00446 if ($arg === '%map') {
00447
00448
00449
00450 $args[$i] = &$map;
00451 }
00452 if (is_int($arg)) {
00453 $args[$i] = isset($path_map[$arg]) ? $path_map[$arg] : '';
00454 }
00455 }
00456 array_unshift($args, $value);
00457 $return = call_user_func_array($function, $args);
00458 }
00459 else {
00460 $return = $function($value);
00461 }
00462
00463 if ($return === FALSE) {
00464 $item['access'] = FALSE;
00465 $map = FALSE;
00466 return FALSE;
00467 }
00468 $map[$index] = $return;
00469 }
00470 }
00471 $item['load_functions'] = $load_functions;
00472 }
00473 return TRUE;
00474 }
00475
00486 function _menu_check_access(&$item, $map) {
00487
00488
00489 $callback = empty($item['access_callback']) ? 0 : trim($item['access_callback']);
00490
00491 if (is_numeric($callback)) {
00492 $item['access'] = (bool)$callback;
00493 }
00494 else {
00495 $arguments = menu_unserialize($item['access_arguments'], $map);
00496
00497
00498 if ($callback == 'user_access') {
00499 $item['access'] = (count($arguments) == 1) ? user_access($arguments[0]) : user_access($arguments[0], $arguments[1]);
00500 }
00501 else {
00502 $item['access'] = call_user_func_array($callback, $arguments);
00503 }
00504 }
00505 }
00506
00532 function _menu_item_localize(&$item, $map, $link_translate = FALSE) {
00533 $callback = $item['title_callback'];
00534 $item['localized_options'] = $item['options'];
00535
00536
00537 if (!$link_translate || (!empty($item['title']) && ($item['title'] == $item['link_title']))) {
00538
00539
00540 if ($callback == 't') {
00541 if (empty($item['title_arguments'])) {
00542 $item['title'] = t($item['title']);
00543 }
00544 else {
00545 $item['title'] = t($item['title'], menu_unserialize($item['title_arguments'], $map));
00546 }
00547 }
00548 elseif ($callback) {
00549 if (empty($item['title_arguments'])) {
00550 $item['title'] = $callback($item['title']);
00551 }
00552 else {
00553 $item['title'] = call_user_func_array($callback, menu_unserialize($item['title_arguments'], $map));
00554 }
00555
00556 if ($callback == 'check_plain') {
00557 $item['localized_options']['html'] = TRUE;
00558 }
00559 }
00560 }
00561 elseif ($link_translate) {
00562 $item['title'] = $item['link_title'];
00563 }
00564
00565
00566 if (!empty($item['description'])) {
00567 $original_description = $item['description'];
00568 $item['description'] = t($item['description']);
00569 if ($link_translate && isset($item['options']['attributes']['title']) && $item['options']['attributes']['title'] == $original_description) {
00570 $item['localized_options']['attributes']['title'] = $item['description'];
00571 }
00572 }
00573 }
00574
00604 function _menu_translate(&$router_item, $map, $to_arg = FALSE) {
00605 $path_map = $map;
00606 if (!_menu_load_objects($router_item, $map)) {
00607
00608 $router_item['access'] = FALSE;
00609 return FALSE;
00610 }
00611 if ($to_arg) {
00612 _menu_link_map_translate($path_map, $router_item['to_arg_functions']);
00613 }
00614
00615
00616 $link_map = explode('/', $router_item['path']);
00617 for ($i = 0; $i < $router_item['number_parts']; $i++) {
00618 if ($link_map[$i] == '%') {
00619 $link_map[$i] = $path_map[$i];
00620 }
00621 }
00622 $router_item['href'] = implode('/', $link_map);
00623 $router_item['options'] = array();
00624 _menu_check_access($router_item, $map);
00625
00626 _menu_item_localize($router_item, $map);
00627
00628 return $map;
00629 }
00630
00641 function _menu_link_map_translate(&$map, $to_arg_functions) {
00642 if ($to_arg_functions) {
00643 $to_arg_functions = unserialize($to_arg_functions);
00644 foreach ($to_arg_functions as $index => $function) {
00645
00646 $arg = $function(!empty($map[$index]) ? $map[$index] : '', $map, $index);
00647 if (!empty($map[$index]) || isset($arg)) {
00648 $map[$index] = $arg;
00649 }
00650 else {
00651 unset($map[$index]);
00652 }
00653 }
00654 }
00655 }
00656
00657 function menu_tail_to_arg($arg, $map, $index) {
00658 return implode('/', array_slice($map, $index));
00659 }
00660
00676 function _menu_link_translate(&$item) {
00677 $item['options'] = unserialize($item['options']);
00678 if ($item['external']) {
00679 $item['access'] = 1;
00680 $map = array();
00681 $item['href'] = $item['link_path'];
00682 $item['title'] = $item['link_title'];
00683 $item['localized_options'] = $item['options'];
00684 }
00685 else {
00686 $map = explode('/', $item['link_path']);
00687 _menu_link_map_translate($map, $item['to_arg_functions']);
00688 $item['href'] = implode('/', $map);
00689
00690
00691 if (strpos($item['href'], '%') !== FALSE) {
00692 $item['access'] = FALSE;
00693 return FALSE;
00694 }
00695
00696 if (!isset($item['access'])) {
00697 if (!_menu_load_objects($item, $map)) {
00698
00699 $item['access'] = FALSE;
00700 return FALSE;
00701 }
00702 _menu_check_access($item, $map);
00703 }
00704
00705 _menu_item_localize($item, $map, TRUE);
00706 }
00707
00708
00709
00710
00711 if (!empty($item['options']['alter'])) {
00712 drupal_alter('translated_menu_link', $item, $map);
00713 }
00714
00715 return $map;
00716 }
00717
00738 function menu_get_object($type = 'node', $position = 1, $path = NULL) {
00739 $router_item = menu_get_item($path);
00740 if (isset($router_item['load_functions'][$position]) && !empty($router_item['map'][$position]) && $router_item['load_functions'][$position] == $type . '_load') {
00741 return $router_item['map'][$position];
00742 }
00743 }
00744
00757 function menu_tree($menu_name = 'navigation') {
00758 static $menu_output = array();
00759
00760 if (!isset($menu_output[$menu_name])) {
00761 $tree = menu_tree_page_data($menu_name);
00762 $menu_output[$menu_name] = menu_tree_output($tree);
00763 }
00764 return $menu_output[$menu_name];
00765 }
00766
00775 function menu_tree_output($tree) {
00776 $output = '';
00777 $items = array();
00778
00779
00780
00781 foreach ($tree as $data) {
00782 if (!$data['link']['hidden']) {
00783 $items[] = $data;
00784 }
00785 }
00786
00787 $num_items = count($items);
00788 foreach ($items as $i => $data) {
00789 $extra_class = NULL;
00790 if ($i == 0) {
00791 $extra_class = 'first';
00792 }
00793 if ($i == $num_items - 1) {
00794 $extra_class = 'last';
00795 }
00796 $link = theme('menu_item_link', $data['link']);
00797 if ($data['below']) {
00798 $output .= theme('menu_item', $link, $data['link']['has_children'], menu_tree_output($data['below']), $data['link']['in_active_trail'], $extra_class);
00799 }
00800 else {
00801 $output .= theme('menu_item', $link, $data['link']['has_children'], '', $data['link']['in_active_trail'], $extra_class);
00802 }
00803 }
00804 return $output ? theme('menu_tree', $output) : '';
00805 }
00806
00822 function menu_tree_all_data($menu_name = 'navigation', $item = NULL) {
00823 static $tree = array();
00824
00825
00826 $mlid = isset($item['mlid']) ? $item['mlid'] : 0;
00827
00828 $cid = 'links:' . $menu_name . ':all-cid:' . $mlid;
00829
00830 if (!isset($tree[$cid])) {
00831
00832 $cache = cache_get($cid, 'cache_menu');
00833 if ($cache && isset($cache->data)) {
00834
00835
00836 $cache = cache_get($cache->data, 'cache_menu');
00837 if ($cache && isset($cache->data)) {
00838 $data = $cache->data;
00839 }
00840 }
00841
00842 if (!isset($data)) {
00843
00844 if ($mlid) {
00845
00846
00847 $args = array(0);
00848 for ($i = 1; $i < MENU_MAX_DEPTH; $i++) {
00849 $args[] = $item["p$i"];
00850 }
00851 $args = array_unique($args);
00852 $placeholders = implode(', ', array_fill(0, count($args), '%d'));
00853 $where = ' AND ml.plid IN (' . $placeholders . ')';
00854 $parents = $args;
00855 $parents[] = $item['mlid'];
00856 }
00857 else {
00858
00859 $where = '';
00860 $args = array();
00861 $parents = array();
00862 }
00863 array_unshift($args, $menu_name);
00864
00865
00866
00867 $data['tree'] = menu_tree_data(db_query("
00868 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, m.description, ml.*
00869 FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path
00870 WHERE ml.menu_name = '%s'" . $where . "
00871 ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", $args), $parents);
00872 $data['node_links'] = array();
00873 menu_tree_collect_node_links($data['tree'], $data['node_links']);
00874
00875 $tree_cid = _menu_tree_cid($menu_name, $data);
00876 if (!cache_get($tree_cid, 'cache_menu')) {
00877 cache_set($tree_cid, $data, 'cache_menu');
00878 }
00879
00880 cache_set($cid, $tree_cid, 'cache_menu');
00881 }
00882
00883 menu_tree_check_access($data['tree'], $data['node_links']);
00884 $tree[$cid] = $data['tree'];
00885 }
00886
00887 return $tree[$cid];
00888 }
00889
00905 function menu_tree_page_data($menu_name = 'navigation') {
00906 static $tree = array();
00907
00908
00909 if ($item = menu_get_item()) {
00910
00911 $cid = 'links:' . $menu_name . ':page-cid:' . $item['href'] . ':' . (int)$item['access'];
00912
00913 if (!isset($tree[$cid])) {
00914
00915 $cache = cache_get($cid, 'cache_menu');
00916 if ($cache && isset($cache->data)) {
00917
00918
00919 $cache = cache_get($cache->data, 'cache_menu');
00920 if ($cache && isset($cache->data)) {
00921 $data = $cache->data;
00922 }
00923 }
00924
00925 if (!isset($data)) {
00926
00927 if ($item['access']) {
00928
00929 $args = array($menu_name, $item['href']);
00930 $placeholders = "'%s'";
00931 if (drupal_is_front_page()) {
00932 $args[] = '<front>';
00933 $placeholders .= ", '%s'";
00934 }
00935 $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 IN (" . $placeholders . ")", $args));
00936
00937 if (empty($parents)) {
00938
00939
00940 $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']));
00941 }
00942
00943 $parents[] = '0';
00944
00945
00946 $args = $parents = array_unique(array_values($parents));
00947 $placeholders = implode(', ', array_fill(0, count($args), '%d'));
00948 $expanded = variable_get('menu_expanded', array());
00949
00950 if (in_array($menu_name, $expanded)) {
00951
00952
00953 do {
00954 $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));
00955 $num_rows = FALSE;
00956 while ($item = db_fetch_array($result)) {
00957 $args[] = $item['mlid'];
00958 $num_rows = TRUE;
00959 }
00960 $placeholders = implode(', ', array_fill(0, count($args), '%d'));
00961 } while ($num_rows);
00962 }
00963 array_unshift($args, $menu_name);
00964 }
00965 else {
00966
00967 $args = array($menu_name, '0');
00968 $placeholders = '%d';
00969 $parents = array();
00970 }
00971
00972
00973
00974 $data['tree'] = menu_tree_data(db_query("
00975 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, m.description, ml.*
00976 FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path
00977 WHERE ml.menu_name = '%s' AND ml.plid IN (" . $placeholders . ")
00978 ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", $args), $parents);
00979 $data['node_links'] = array();
00980 menu_tree_collect_node_links($data['tree'], $data['node_links']);
00981
00982 $tree_cid = _menu_tree_cid($menu_name, $data);
00983 if (!cache_get($tree_cid, 'cache_menu')) {
00984 cache_set($tree_cid, $data, 'cache_menu');
00985 }
00986
00987 cache_set($cid, $tree_cid, 'cache_menu');
00988 }
00989
00990 menu_tree_check_access($data['tree'], $data['node_links']);
00991 $tree[$cid] = $data['tree'];
00992 }
00993 return $tree[$cid];
00994 }
00995
00996 return array();
00997 }
00998
01002 function _menu_tree_cid($menu_name, $data) {
01003 return 'links:' . $menu_name . ':tree-data:' . md5(serialize($data));
01004 }
01005
01009 function menu_tree_collect_node_links(&$tree, &$node_links) {
01010 foreach ($tree as $key => $v) {
01011 if ($tree[$key]['link']['router_path'] == 'node/%') {
01012 $nid = substr($tree[$key]['link']['link_path'], 5);
01013 if (is_numeric($nid)) {
01014 $node_links[$nid][$tree[$key]['link']['mlid']] = &$tree[$key]['link'];
01015 $tree[$key]['link']['access'] = FALSE;
01016 }
01017 }
01018 if ($tree[$key]['below']) {
01019 menu_tree_collect_node_links($tree[$key]['below'], $node_links);
01020 }
01021 }
01022 }
01023
01027 function menu_tree_check_access(&$tree, $node_links = array()) {
01028
01029 if ($node_links) {
01030
01031 $nids = array_keys($node_links);
01032 $placeholders = '%d' . str_repeat(', %d', count($nids) - 1);
01033 $result = db_query(db_rewrite_sql("SELECT n.nid FROM {node} n WHERE n.status = 1 AND n.nid IN (" . $placeholders . ")"), $nids);
01034 while ($node = db_fetch_array($result)) {
01035 $nid = $node['nid'];
01036 foreach ($node_links[$nid] as $mlid => $link) {
01037 $node_links[$nid][$mlid]['access'] = TRUE;
01038 }
01039 }
01040 }
01041 _menu_tree_check_access($tree);
01042 return;
01043 }
01044
01048 function _menu_tree_check_access(&$tree) {
01049 $new_tree = array();
01050 foreach ($tree as $key => $v) {
01051 $item = &$tree[$key]['link'];
01052 _menu_link_translate($item);
01053 if ($item['access']) {
01054 if ($tree[$key]['below']) {
01055 _menu_tree_check_access($tree[$key]['below']);
01056 }
01057
01058
01059
01060 $new_tree[(50000 + $item['weight']) . ' ' . $item['title'] . ' ' . $item['mlid']] = $tree[$key];
01061 }
01062 }
01063
01064 ksort($new_tree);
01065 $tree = $new_tree;
01066 }
01067
01081 function menu_tree_data($result = NULL, $parents = array(), $depth = 1) {
01082 list(, $tree) = _menu_tree_data($result, $parents, $depth);
01083 return $tree;
01084 }
01085
01093 function _menu_tree_data($result, $parents, $depth, $previous_element = '') {
01094 $remnant = NULL;
01095 $tree = array();
01096 while ($item = db_fetch_array($result)) {
01097
01098
01099 $item['in_active_trail'] = in_array($item['mlid'], $parents);
01100
01101 if ($item['depth'] > $depth) {
01102
01103 list($item, $below) = _menu_tree_data($result, $parents, $item['depth'], $item);
01104 if ($previous_element) {
01105 $tree[$previous_element['mlid']] = array(
01106 'link' => $previous_element,
01107 'below' => $below,
01108 );
01109 }
01110 else {
01111 $tree = $below;
01112 }
01113
01114 if (!isset($item) || $item['depth'] < $depth) {
01115 return array($item, $tree);
01116 }
01117
01118 $previous_element = $item;
01119 }
01120
01121 elseif ($item['depth'] == $depth) {
01122 if ($previous_element) {
01123
01124 $tree[$previous_element['mlid']] = array(
01125 'link' => $previous_element,
01126 'below' => FALSE,
01127 );
01128 }
01129
01130 $previous_element = $item;
01131 }
01132
01133 else {
01134 $remnant = $item;
01135 break;
01136 }
01137 }
01138 if ($previous_element) {
01139
01140 $tree[$previous_element['mlid']] = array(
01141 'link' => $previous_element,
01142 'below' => FALSE,
01143 );
01144 }
01145 return array($remnant, $tree);
01146 }
01147
01153 function theme_menu_item_link($link) {
01154 if (empty($link['localized_options'])) {
01155 $link['localized_options'] = array();
01156 }
01157
01158 return l($link['title'], $link['href'], $link['localized_options']);
01159 }
01160
01166 function theme_menu_tree($tree) {
01167 return '<ul class="menu">' . $tree . '</ul>';
01168 }
01169
01175 function theme_menu_item($link, $has_children, $menu = '', $in_active_trail = FALSE, $extra_class = NULL) {
01176 $class = ($menu ? 'expanded' : ($has_children ? 'collapsed' : 'leaf'));
01177 if (!empty($extra_class)) {
01178 $class .= ' ' . $extra_class;
01179 }
01180 if ($in_active_trail) {
01181 $class .= ' active-trail';
01182 }
01183 return '<li class="' . $class . '">' . $link . $menu . "</li>\n";
01184 }
01185
01191 function theme_menu_local_task($link, $active = FALSE) {
01192 return '<li ' . ($active ? 'class="active" ' : '') . '>' . $link . "</li>\n";
01193 }
01194
01198 function drupal_help_arg($arg = array()) {
01199
01200 return $arg + array('', '', '', '', '', '', '', '', '', '', '', '');
01201 }
01202
01206 function menu_get_active_help() {
01207 $output = '';
01208 $router_path = menu_tab_root_path();
01209
01210 $arg = drupal_help_arg(arg(NULL));
01211 $empty_arg = drupal_help_arg();
01212
01213 foreach (module_list() as $name) {
01214 if (module_hook($name, 'help')) {
01215
01216 if ($help = module_invoke($name, 'help', $router_path, $arg)) {
01217 $output .= $help . "\n";
01218 }
01219
01220
01221 if ($arg[0] == "admin" && module_exists('help') && module_invoke($name, 'help', 'admin/help#' . $arg[2], $empty_arg) && $help) {
01222 $output .= theme("more_help_link", url('admin/help/' . $arg[2]));
01223 }
01224 }
01225 }
01226 return $output;
01227 }
01228
01232 function menu_get_names($reset = FALSE) {
01233 static $names;
01234
01235 if ($reset || empty($names)) {
01236 $names = array();
01237 $result = db_query("SELECT DISTINCT(menu_name) FROM {menu_links} ORDER BY menu_name");
01238 while ($name = db_fetch_array($result)) {
01239 $names[] = $name['menu_name'];
01240 }
01241 }
01242 return $names;
01243 }
01244
01248 function menu_list_system_menus() {
01249 return array('navigation', 'primary-links', 'secondary-links');
01250 }
01251
01255 function menu_primary_links() {
01256 return menu_navigation_links(variable_get('menu_primary_links_source', 'primary-links'));
01257 }
01258
01262 function menu_secondary_links() {
01263
01264
01265
01266 if (variable_get('menu_secondary_links_source', 'secondary-links') == variable_get('menu_primary_links_source', 'primary-links')) {
01267 return menu_navigation_links(variable_get('menu_primary_links_source', 'primary-links'), 1);
01268 }
01269 else {
01270 return menu_navigation_links(variable_get('menu_secondary_links_source', 'secondary-links'), 0);
01271 }
01272 }
01273
01284 function menu_navigation_links($menu_name, $level = 0) {
01285
01286 if (empty($menu_name)) {
01287 return array();
01288 }
01289
01290
01291 $tree = menu_tree_page_data($menu_name);
01292
01293
01294 while ($level-- > 0 && $tree) {
01295
01296 while ($item = array_shift($tree)) {
01297 if ($item['link']['in_active_trail']) {
01298
01299 $tree = empty($item['below']) ? array() : $item['below'];
01300 break;
01301 }
01302 }
01303 }
01304
01305
01306 $links = array();
01307 foreach ($tree as $item) {
01308 if (!$item['link']['hidden']) {
01309 $l = $item['link']['localized_options'];
01310 $l['href'] = $item['link']['href'];
01311 $l['title'] = $item['link']['title'];
01312 if ($item['link']['in_active_trail']) {
01313 $l['attributes'] = array('class' => 'active-trail');
01314 }
01315
01316 $links['menu-' . $item['link']['mlid']] = $l;
01317 }
01318 }
01319 return $links;
01320 }
01321
01334 function menu_local_tasks($level = 0, $return_root = FALSE) {
01335 static $tabs;
01336 static $root_path;
01337
01338 if (!isset($tabs)) {
01339 $tabs = array();
01340
01341 $router_item = menu_get_item();
01342 if (!$router_item || !$router_item['access']) {
01343 return '';
01344 }
01345
01346 $result = db_query("SELECT * FROM {menu_router} WHERE tab_root = '%s' ORDER BY weight, title", $router_item['tab_root']);
01347 $map = arg();
01348 $children = array();
01349 $tasks = array();
01350 $root_path = $router_item['path'];
01351
01352 while ($item = db_fetch_array($result)) {
01353 _menu_translate($item, $map, TRUE);
01354 if ($item['tab_parent']) {
01355
01356 $children[$item['tab_parent']][$item['path']] = $item;
01357 }
01358
01359 $tasks[$item['path']] = $item;
01360 }
01361
01362
01363 $path = $router_item['path'];
01364
01365
01366 $depth = 1001;
01367 while (isset($children[$path])) {
01368 $tabs_current = '';
01369 $next_path = '';
01370 $count = 0;
01371 foreach ($children[$path] as $item) {
01372 if ($item['access']) {
01373 $count++;
01374
01375 if ($item['type'] == MENU_DEFAULT_LOCAL_TASK) {
01376
01377 for ($p = $item['tab_parent']; $tasks[$p]['type'] == MENU_DEFAULT_LOCAL_TASK; $p = $tasks[$p]['tab_parent']);
01378 $link = theme('menu_item_link', array('href' => $tasks[$p]['href']) + $item);
01379 $tabs_current .= theme('menu_local_task', $link, TRUE);
01380 $next_path = $item['path'];
01381 }
01382 else {
01383 $link = theme('menu_item_link', $item);
01384 $tabs_current .= theme('menu_local_task', $link);
01385 }
01386 }
01387 }
01388 $path = $next_path;
01389 $tabs[$depth]['count'] = $count;
01390 $tabs[$depth]['output'] = $tabs_current;
01391 $depth++;
01392 }
01393
01394
01395 $parent = $router_item['tab_parent'];
01396 $path = $router_item['path'];
01397 $current = $router_item;
01398 $depth = 1000;
01399 while (isset($children[$parent])) {
01400 $tabs_current = '';
01401 $next_path = '';
01402 $next_parent = '';
01403 $count = 0;
01404 foreach ($children[$parent] as $item) {
01405 if ($item['access']) {
01406 $count++;
01407 if ($item['type'] == MENU_DEFAULT_LOCAL_TASK) {
01408
01409 for ($p = $item['tab_parent']; $tasks[$p]['type'] == MENU_DEFAULT_LOCAL_TASK; $p = $tasks[$p]['tab_parent']);
01410 $link = theme('menu_item_link', array('href' => $tasks[$p]['href']) + $item);
01411 if ($item['path'] == $router_item['path']) {
01412 $root_path = $tasks[$p]['path'];
01413 }
01414 }
01415 else {
01416 $link = theme('menu_item_link', $item);
01417 }
01418
01419 if ($item['path'] == $path) {
01420 $tabs_current .= theme('menu_local_task', $link, TRUE);
01421 $next_path = $item['tab_parent'];
01422 if (isset($tasks[$next_path])) {
01423 $next_parent = $tasks[$next_path]['tab_parent'];
01424 }
01425 }
01426 else {
01427 $tabs_current .= theme('menu_local_task', $link);
01428 }
01429 }
01430 }
01431 $path = $next_path;
01432 $parent = $next_parent;
01433 $tabs[$depth]['count'] = $count;
01434 $tabs[$depth]['output'] = $tabs_current;
01435 $depth--;
01436 }
01437
01438 ksort($tabs);
01439
01440 $tabs = array_values($tabs);
01441 }
01442
01443 if ($return_root) {
01444 return $root_path;
01445 }
01446 else {
01447
01448 return (isset($tabs[$level]) && $tabs[$level]['count'] > 1) ? $tabs[$level]['output'] : '';
01449 }
01450 }
01451
01455 function menu_primary_local_tasks() {
01456 return menu_local_tasks(0);
01457 }
01458
01462 function menu_secondary_local_tasks() {
01463 return menu_local_tasks(1);
01464 }
01465
01469 function menu_tab_root_path() {
01470 return menu_local_tasks(0, TRUE);
01471 }
01472
01478 function theme_menu_local_tasks() {
01479 $output = '';
01480
01481 if ($primary = menu_primary_local_tasks()) {
01482 $output .= "<ul class=\"tabs primary\">\n" . $primary . "</ul>\n";
01483 }
01484 if ($secondary = menu_secondary_local_tasks()) {
01485 $output .= "<ul class=\"tabs secondary\">\n" . $secondary . "</ul>\n";
01486 }
01487
01488 return $output;
01489 }
01490
01494 function menu_set_active_menu_name($menu_name = NULL) {
01495 static $active;
01496
01497 if (isset($menu_name)) {
01498 $active = $menu_name;
01499 }
01500 elseif (!isset($active)) {
01501 $active = 'navigation';
01502 }
01503 return $active;
01504 }
01505
01509 function menu_get_active_menu_name() {
01510 return menu_set_active_menu_name();
01511 }
01512
01523 function menu_set_active_item($path) {
01524 $_GET['q'] = $path;
01525 }
01526
01530 function menu_set_active_trail($new_trail = NULL) {
01531 static $trail;
01532
01533 if (isset($new_trail)) {
01534 $trail = $new_trail;
01535 }
01536 elseif (!isset($trail)) {
01537 $trail = array();
01538 $trail[] = array('title' => t('Home'), 'href' => '<front>', 'localized_options' => array(), 'type' => 0);
01539 $item = menu_get_item();
01540
01541
01542 if ($item['tab_parent']) {
01543
01544
01545
01546
01547 $parts = explode('/', $item['tab_root']);
01548 $args = arg();
01549
01550 foreach ($parts as $index => $part) {
01551 if ($part == '%') {
01552 $parts[$index] = $args[$index];
01553 }
01554 }
01555
01556 $root_item = menu_get_item(implode('/', $parts));
01557 if ($root_item && $root_item['access']) {
01558 $item = $root_item;
01559 }
01560 }
01561
01562 $tree = menu_tree_page_data(menu_get_active_menu_name());
01563 list($key, $curr) = each($tree);
01564
01565 while ($curr) {
01566
01567 if ($curr['link']['href'] == $item['href']) {
01568 $trail[] = $curr['link'];
01569 $curr = FALSE;
01570 }
01571 else {
01572
01573 if ($curr['below'] && $curr['link']['in_active_trail']) {
01574 $trail[] = $curr['link'];
01575 $tree = $curr['below'];
01576 }
01577 list($key, $curr) = each($tree);
01578 }
01579 }
01580
01581
01582 $last = count($trail) - 1;
01583 if ($trail[$last]['href'] != $item['href'] && !(bool)($item['type'] & MENU_IS_LOCAL_TASK) && !drupal_is_front_page()) {
01584 $trail[] = $item;
01585 }
01586 }
01587 return $trail;
01588 }
01589
01593 function menu_get_active_trail() {
01594 return menu_set_active_trail();
01595 }
01596
01600 function menu_get_active_breadcrumb() {
01601 $breadcrumb = array();
01602
01603
01604 if (drupal_is_front_page()) {
01605 return $breadcrumb;
01606 }
01607
01608 $item = menu_get_item();
01609 if ($item && $item['access']) {
01610 $active_trail = menu_get_active_trail();
01611
01612 foreach ($active_trail as $parent) {
01613 $breadcrumb[] = l($parent['title'], $parent['href'], $parent['localized_options']);
01614 }
01615 $end = end($active_trail);
01616
01617
01618 if ($item['href'] == $end['href'] || ($item['type'] == MENU_DEFAULT_LOCAL_TASK && $end['href'] != '<front>')) {
01619 array_pop($breadcrumb);
01620 }
01621 }
01622 return $breadcrumb;
01623 }
01624
01628 function menu_get_active_title() {
01629 $active_trail = menu_get_active_trail();
01630
01631 foreach (array_reverse($active_trail) as $item) {
01632 if (!(bool)($item['type'] & MENU_IS_LOCAL_TASK)) {
01633 return $item['title'];
01634 }
01635 }
01636 }
01637
01651 function menu_link_load($mlid) {
01652 if (is_numeric($mlid) && $item = db_fetch_array(db_query("SELECT m.*, ml.* FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path WHERE ml.mlid = %d", $mlid))) {
01653 _menu_link_translate($item);
01654 return $item;
01655 }
01656 return FALSE;
01657 }
01658
01662 function menu_cache_clear($menu_name = 'navigation') {
01663 static $cache_cleared = array();
01664
01665 if (empty($cache_cleared[$menu_name])) {
01666 cache_clear_all('links:' . $menu_name . ':', 'cache_menu', TRUE);
01667 $cache_cleared[$menu_name] = 1;
01668 }
01669 elseif ($cache_cleared[$menu_name] == 1) {
01670 register_shutdown_function('cache_clear_all', 'links:' . $menu_name . ':', 'cache_menu', TRUE);
01671 $cache_cleared[$menu_name] = 2;
01672 }
01673 }
01674
01679 function menu_cache_clear_all() {
01680 cache_clear_all('*', 'cache_menu', TRUE);
01681 }
01682
01693 function menu_rebuild() {
01694 variable_del('menu_rebuild_needed');
01695 menu_cache_clear_all();
01696 $menu = menu_router_build(TRUE);
01697 _menu_navigation_links_rebuild($menu);
01698
01699 _menu_clear_page_cache();
01700 if (defined('MAINTENANCE_MODE')) {
01701 variable_set('menu_rebuild_needed', TRUE);
01702 }
01703 }
01704
01708 function menu_router_build($reset = FALSE) {
01709 static $menu;
01710
01711 if (!isset($menu) || $reset) {
01712 if (!$reset && ($cache = cache_get('router:', 'cache_menu')) && isset($cache->data)) {
01713 $menu = $cache->data;
01714 }
01715 else {
01716 db_query('DELETE FROM {menu_router}');
01717
01718
01719 $callbacks = array();
01720 foreach (module_implements('menu', NULL, TRUE) as $module) {
01721 $router_items = call_user_func($module . '_menu');
01722 if (isset($router_items) && is_array($router_items)) {
01723 foreach (array_keys($router_items) as $path) {
01724 $router_items[$path]['module'] = $module;
01725 }
01726 $callbacks = array_merge($callbacks, $router_items);
01727 }
01728 }
01729
01730 drupal_alter('menu', $callbacks);
01731 $menu = _menu_router_build($callbacks);
01732 cache_set('router:', $menu, 'cache_menu');
01733 }
01734 }
01735 return $menu;
01736 }
01737
01741 function _menu_link_build($item) {
01742 if ($item['type'] == MENU_CALLBACK) {
01743 $item['hidden'] = -1;
01744 }
01745 elseif ($item['type'] == MENU_SUGGESTED_ITEM) {
01746 $item['hidden'] = 1;
01747 }
01748
01749
01750 $item['module'] = 'system';
01751 $item += array(
01752 'menu_name' => 'navigation',
01753 'link_title' => $item['title'],
01754 'link_path' => $item['path'],
01755 'hidden' => 0,
01756 'options' => empty($item['description']) ? array() : array('attributes' => array('title' => $item['description'])),
01757 );
01758 return $item;
01759 }
01760
01764 function _menu_navigation_links_rebuild($menu) {
01765
01766 $menu_links = array();
01767 foreach ($menu as $path => $item) {
01768 if ($item['_visible']) {
01769 $item = _menu_link_build($item);
01770 $menu_links[$path] = $item;
01771 $sort[$path] = $item['_number_parts'];
01772 }
01773 }
01774 if ($menu_links) {
01775
01776 array_multisort($sort, SORT_NUMERIC, $menu_links);
01777
01778 foreach ($menu_links as $item) {
01779 $existing_item = db_fetch_array(db_query("SELECT mlid, menu_name, plid, customized, has_children, updated FROM {menu_links} WHERE link_path = '%s' AND module = '%s'", $item['link_path'], 'system'));
01780 if ($existing_item) {
01781 $item['mlid'] = $existing_item['mlid'];
01782 $item['menu_name'] = $existing_item['menu_name'];
01783 $item['plid'] = $existing_item['plid'];
01784 $item['has_children'] = $existing_item['has_children'];
01785 $item['updated'] = $existing_item['updated'];
01786 }
01787 if (!$existing_item || !$existing_item['customized']) {
01788 menu_link_save($item);
01789 }
01790 }
01791 }
01792 $placeholders = db_placeholders($menu, 'varchar');
01793 $paths = array_keys($menu);
01794
01795 $result = db_query("SELECT ml.link_path, ml.mlid, ml.router_path, ml.updated FROM {menu_links} ml WHERE ml.updated = 1 OR (router_path NOT IN ($placeholders) AND external = 0 AND customized = 1)", $paths);
01796 while ($item = db_fetch_array($result)) {
01797 $router_path = _menu_find_router_path($menu, $item['link_path']);
01798 if (!empty($router_path) && ($router_path != $item['router_path'] || $item['updated'])) {
01799
01800
01801 $updated = $item['updated'] && $router_path != $item['link_path'];
01802 db_query("UPDATE {menu_links} SET router_path = '%s', updated = %d WHERE mlid = %d", $router_path, $updated, $item['mlid']);
01803 }
01804 }
01805
01806 $result = db_query("SELECT * FROM {menu_links} WHERE router_path NOT IN ($placeholders) AND external = 0 AND updated = 0 AND customized = 0 ORDER BY depth DESC", $paths);
01807
01808
01809 while ($item = db_fetch_array($result)) {
01810 _menu_delete_item($item, TRUE);
01811 }
01812 }
01813
01822 function menu_link_delete($mlid, $path = NULL) {
01823 if (isset($mlid)) {
01824 _menu_delete_item(db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE mlid = %d", $mlid)));
01825 }
01826 else {
01827 $result = db_query("SELECT * FROM {menu_links} WHERE link_path = '%s'", $path);
01828 while ($link = db_fetch_array($result)) {
01829 _menu_delete_item($link);
01830 }
01831 }
01832 }
01833
01842 function _menu_delete_item($item, $force = FALSE) {
01843 if ($item && ($item['module'] != 'system' || $item['updated'] || $force)) {
01844
01845 if ($item['has_children']) {
01846 $result = db_query("SELECT mlid FROM {menu_links} WHERE plid = %d", $item['mlid']);
01847 while ($m = db_fetch_array($result)) {
01848 $child = menu_link_load($m['mlid']);
01849 $child['plid'] = $item['plid'];
01850 menu_link_save($child);
01851 }
01852 }
01853 db_query('DELETE FROM {menu_links} WHERE mlid = %d', $item['mlid']);
01854
01855
01856 _menu_update_parental_status($item);
01857 menu_cache_clear($item['menu_name']);
01858 _menu_clear_page_cache();
01859 }
01860 }
01861
01876 function menu_link_save(&$item) {
01877 $menu = menu_router_build();
01878
01879 drupal_alter('menu_link', $item, $menu);
01880
01881
01882
01883 $item['_external'] = menu_path_is_external($item['link_path']) || $item['link_path'] == '<front>';
01884
01885 $item += array(
01886 'menu_name' => 'navigation',
01887 'weight' => 0,
01888 'link_title' => '',
01889 'hidden' => 0,
01890 'has_children' => 0,
01891 'expanded' => 0,
01892 'options' => array(),
01893 'module' => 'menu',
01894 'customized' => 0,
01895 'updated' => 0,
01896 );
01897 $existing_item = FALSE;
01898 if (isset($item['mlid'])) {
01899 $existing_item = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE mlid = %d", $item['mlid']));
01900 }
01901
01902 if (isset($item['plid'])) {
01903 $parent = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE mlid = %d", $item['plid']));
01904 }
01905 else {
01906
01907 $parent_path = $item['link_path'];
01908 $where = "WHERE link_path = '%s'";
01909
01910
01911 if ($item['module'] == 'system') {
01912 $where .= " AND module = '%s'";
01913 $arg2 = 'system';
01914 }
01915 else {
01916
01917 $where .= " AND menu_name = '%s'";
01918 $arg2 = $item['menu_name'];
01919 }
01920 do {
01921 $parent = FALSE;
01922 $parent_path = substr($parent_path, 0, strrpos($parent_path, '/'));
01923 $result = db_query("SELECT COUNT(*) FROM {menu_links} " . $where, $parent_path, $arg2);
01924
01925 if (db_result($result) == 1) {
01926 $parent = db_fetch_array(db_query("SELECT * FROM {menu_links} " . $where, $parent_path, $arg2));
01927 }
01928 } while ($parent === FALSE && $parent_path);
01929 }
01930 if ($parent !== FALSE) {
01931 $item['menu_name'] = $parent['menu_name'];
01932 }
01933 $menu_name = $item['menu_name'];
01934
01935
01936 if (empty($parent['mlid']) || $parent['hidden'] < 0) {
01937 $item['plid'] = 0;
01938 }
01939 else {
01940 $item['plid'] = $parent['mlid'];
01941 }
01942
01943 if (!$existing_item) {
01944 db_query("INSERT INTO {menu_links} (
01945 menu_name, plid, link_path,
01946 hidden, external, has_children,
01947 expanded, weight,
01948 module, link_title, options,
01949 customized, updated) VALUES (
01950 '%s', %d, '%s',
01951 %d, %d, %d,
01952 %d, %d,
01953 '%s', '%s', '%s', %d, %d)",
01954 $item['menu_name'], $item['plid'], $item['link_path'],
01955 $item['hidden'], $item['_external'], $item['has_children'],
01956 $item['expanded'], $item['weight'],
01957 $item['module'], $item['link_title'], serialize($item['options']),
01958 $item['customized'], $item['updated']);
01959 $item['mlid'] = db_last_insert_id('menu_links', 'mlid');
01960 }
01961
01962 if (!$item['plid']) {
01963 $item['p1'] = $item['mlid'];
01964 for ($i = 2; $i <= MENU_MAX_DEPTH; $i++) {
01965 $item["p$i"] = 0;
01966 }
01967 $item['depth'] = 1;
01968 }
01969 else {
01970
01971 if ($item['has_children'] && $existing_item) {
01972 $limit = MENU_MAX_DEPTH - menu_link_children_relative_depth($existing_item) - 1;
01973 }
01974 else {
01975 $limit = MENU_MAX_DEPTH - 1;
01976 }
01977 if ($parent['depth'] > $limit) {
01978 return FALSE;
01979 }
01980 $item['depth'] = $parent['depth'] + 1;
01981 _menu_link_parents_set($item, $parent);
01982 }
01983
01984 if ($existing_item && ($item['plid'] != $existing_item['plid'] || $menu_name != $existing_item['menu_name'])) {
01985 _menu_link_move_children($item, $existing_item);
01986 }
01987
01988
01989 if (!isset($_SESSION['system_update_6021']) && (empty($item['router_path']) || !$existing_item || ($existing_item['link_path'] != $item['link_path']))) {
01990 if ($item['_external']) {
01991 $item['router_path'] = '';
01992 }
01993 else {
01994
01995 $item['parts'] = explode('/', $item['link_path'], MENU_MAX_PARTS);
01996 $item['router_path'] = _menu_find_router_path($menu, $item['link_path']);
01997 }
01998 }
01999 db_query("UPDATE {menu_links} SET menu_name = '%s', plid = %d, link_path = '%s',
02000 router_path = '%s', hidden = %d, external = %d, has_children = %d,
02001 expanded = %d, weight = %d, depth = %d,
02002 p1 = %d, p2 = %d, p3 = %d, p4 = %d, p5 = %d, p6 = %d, p7 = %d, p8 = %d, p9 = %d,
02003 module = '%s', link_title = '%s', options = '%s', customized = %d WHERE mlid = %d",
02004 $item['menu_name'], $item['plid'], $item['link_path'],
02005 $item['router_path'], $item['hidden'], $item['_external'], $item['has_children'],
02006 $item['expanded'], $item['weight'], $item['depth'],
02007 $item['p1'], $item['p2'], $item['p3'], $item['p4'], $item['p5'], $item['p6'], $item['p7'], $item['p8'], $item['p9'],
02008 $item['module'], $item['link_title'], serialize($item['options']), $item['customized'], $item['mlid']);
02009
02010 _menu_update_parental_status($item);
02011 menu_cache_clear($menu_name);
02012 if ($existing_item && $menu_name != $existing_item['menu_name']) {
02013 menu_cache_clear($existing_item['menu_name']);
02014 }
02015
02016 _menu_clear_page_cache();
02017 return $item['mlid'];
02018 }
02019
02023 function _menu_clear_page_cache() {
02024 static $cache_cleared = 0;
02025
02026
02027
02028 if (empty($cache_cleared)) {
02029 cache_clear_all();
02030
02031 _menu_set_expanded_menus();
02032 $cache_cleared = 1;
02033 }
02034 elseif ($cache_cleared == 1) {
02035 register_shutdown_function('cache_clear_all');
02036
02037 register_shutdown_function('_menu_set_expanded_menus');
02038 $cache_cleared = 2;
02039 }
02040 }
02041
02045 function _menu_set_expanded_menus() {
02046 $names = array();
02047 $result = db_query("SELECT menu_name FROM {menu_links} WHERE expanded != 0 GROUP BY menu_name");
02048 while ($n = db_fetch_array($result)) {
02049 $names[] = $n['menu_name'];
02050 }
02051 variable_set('menu_expanded', $names);
02052 }
02053
02065 function _menu_find_router_path($menu, $link_path) {
02066 $parts = explode('/', $link_path, MENU_MAX_PARTS);
02067 $router_path = $link_path;
02068 if (!isset($menu[$router_path])) {
02069 list($ancestors) = menu_get_ancestors($parts);
02070 $ancestors[] = '';
02071 foreach ($ancestors as $key => $router_path) {
02072 if (isset($menu[$router_path])) {
02073 break;
02074 }
02075 }
02076 }
02077 return $router_path;
02078 }
02079
02095 function menu_link_maintain($module, $op, $link_path, $link_title) {
02096 switch ($op) {
02097 case 'insert':
02098 $menu_link = array(
02099 'link_title' => $link_title,
02100 'link_path' => $link_path,
02101 'module' => $module,
02102 );
02103 return menu_link_save($menu_link);
02104 break;
02105 case 'update':
02106 db_query("UPDATE {menu_links} SET link_title = '%s' WHERE link_path = '%s' AND customized = 0 AND module = '%s'", $link_title, $link_path, $module);
02107 menu_cache_clear();
02108 break;
02109 case 'delete':
02110 menu_link_delete(NULL, $link_path);
02111 break;
02112 }
02113 }
02114
02127 function menu_link_children_relative_depth($item) {
02128 $i = 1;
02129 $match = '';
02130 $args[] = $item['menu_name'];
02131 $p = 'p1';
02132 while ($i <= MENU_MAX_DEPTH && $item[$p]) {
02133 $match .= " AND $p = %d";
02134 $args[] = $item[$p];
02135 $p = 'p' . ++$i;
02136 }
02137
02138 $max_depth = db_result(db_query_range("SELECT depth FROM {menu_links} WHERE menu_name = '%s'" . $match . " ORDER BY depth DESC", $args, 0, 1));
02139
02140 return ($max_depth > $item['depth']) ? $max_depth - $item['depth'] : 0;
02141 }
02142
02149 function _menu_link_move_children($item, $existing_item) {
02150
02151 $args[] = $item['menu_name'];
02152 $set[] = "menu_name = '%s'";
02153
02154 $i = 1;
02155 while ($i <= $item['depth']) {
02156 $p = 'p' . $i++;
02157 $set[] = "$p = %d";
02158 $args[] = $item[$p];
02159 }
02160 $j = $existing_item['depth'] + 1;
02161 while ($i <= MENU_MAX_DEPTH && $j <= MENU_MAX_DEPTH) {
02162 $set[] = 'p' . $i++ . ' = p' . $j++;
02163 }
02164 while ($i <= MENU_MAX_DEPTH) {
02165 $set[] = 'p' . $i++ . ' = 0';
02166 }
02167
02168 $shift = $item['depth'] - $existing_item['depth'];
02169 if ($shift < 0) {
02170 $args[] = -$shift;
02171 $set[] = 'depth = depth - %d';
02172 }
02173 elseif ($shift > 0) {
02174
02175
02176
02177
02178 $set = array_reverse($set);
02179 $args = array_reverse($args);
02180
02181 $args[] = $shift;
02182 $set[] = 'depth = depth + %d';
02183 }
02184 $where[] = "menu_name = '%s'";
02185 $args[] = $existing_item['menu_name'];
02186 $p = 'p1';
02187 for ($i = 1; $i <= MENU_MAX_DEPTH && $existing_item[$p]; $p = 'p' . ++$i) {
02188 $where[] = "$p = %d";
02189 $args[] = $existing_item[$p];
02190 }
02191
02192 db_query("UPDATE {menu_links} SET " . implode(', ', $set) . " WHERE " . implode(' AND ', $where), $args);
02193
02194 _menu_update_parental_status($existing_item, TRUE);
02195 }
02196
02200 function _menu_update_parental_status($item, $exclude = FALSE) {
02201
02202 if ($item['plid']) {
02203
02204 $where = $exclude ? " AND mlid != %d" : '';
02205
02206 $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));
02207 db_query("UPDATE {menu_links} SET has_children = %d WHERE mlid = %d", $parent_has_children, $item['plid']);
02208 }
02209 }
02210
02214 function _menu_link_parents_set(&$item, $parent) {
02215 $i = 1;
02216 while ($i < $item['depth']) {
02217 $p = 'p' . $i++;
02218 $item[$p] = $parent[$p];
02219 }
02220 $p = 'p' . $i++;
02221
02222 $item[$p] = $item['mlid'];
02223 while ($i <= MENU_MAX_DEPTH) {
02224 $p = 'p' . $i++;
02225 $item[$p] = 0;
02226 }
02227 }
02228
02232 function _menu_router_build($callbacks) {
02233
02234
02235 $menu = array();
02236 foreach ($callbacks as $path => $item) {
02237 $load_functions = array();
02238 $to_arg_functions = array();
02239 $fit = 0;
02240 $move = FALSE;
02241
02242 $parts = explode('/', $path, MENU_MAX_PARTS);
02243 $number_parts = count($parts);
02244
02245
02246 $slashes = $number_parts - 1;
02247
02248 foreach ($parts as $k => $part) {
02249 $match = FALSE;
02250 if (preg_match('/^%([a-z_]*)$/', $part, $matches)) {
02251 if (empty($matches[1])) {
02252 $match = TRUE;
02253 $load_functions[$k] = NULL;
02254 }
02255 else {
02256 if (drupal_function_exists($matches[1] . '_to_arg')) {
02257 $to_arg_functions[$k] = $matches[1] . '_to_arg';
02258 $load_functions[$k] = NULL;
02259 $match = TRUE;
02260 }
02261 if (drupal_function_exists($matches[1] . '_load')) {
02262 $function = $matches[1] . '_load';
02263
02264
02265
02266 $load_functions[$k] = isset($item['load arguments']) ? array($function => $item['load arguments']) : $function;
02267 $match = TRUE;
02268 }
02269 }
02270 }
02271 if ($match) {
02272 $parts[$k] = '%';
02273 }
02274 else {
02275 $fit |= 1 << ($slashes - $k);
02276 }
02277 }
02278 if ($fit) {
02279 $move = TRUE;
02280 }
02281 else {
02282
02283 $fit = (1 << $number_parts) - 1;
02284 }
02285 $masks[$fit] = 1;
02286 $item['load_functions'] = empty($load_functions) ? '' : serialize($load_functions);
02287 $item['to_arg_functions'] = empty($to_arg_functions) ? '' : serialize($to_arg_functions);
02288 $item += array(
02289 'title' => '',
02290 'weight' => 0,
02291 'type' => MENU_NORMAL_ITEM,
02292 '_number_parts' => $number_parts,
02293 '_parts' => $parts,
02294 '_fit' => $fit,
02295 );
02296 $item += array(
02297 '_visible' => (bool)($item['type'] & MENU_VISIBLE_IN_BREADCRUMB),
02298 '_tab' => (bool)($item['type'] & MENU_IS_LOCAL_TASK),
02299 );
02300 if ($move) {
02301 $new_path = implode('/', $item['_parts']);
02302 $menu[$new_path] = $item;
02303 $sort[$new_path] = $number_parts;
02304 }
02305 else {
02306 $menu[$path] = $item;
02307 $sort[$path] = $number_parts;
02308 }
02309 }
02310 array_multisort($sort, SORT_NUMERIC, $menu);
02311
02312
02313 foreach ($menu as $path => $v) {
02314 $item = &$menu[$path];
02315 if (!$item['_tab']) {
02316
02317 $item['tab_parent'] = '';
02318 $item['tab_root'] = $path;
02319 }
02320 for ($i = $item['_number_parts'] - 1; $i; $i--) {
02321 $parent_path = implode('/', array_slice($item['_parts'], 0, $i));
02322 if (isset($menu[$parent_path])) {
02323
02324 $parent = $menu[$parent_path];
02325
02326 if (!isset($item['tab_parent'])) {
02327
02328 $item['tab_parent'] = $parent_path;
02329 }
02330 if (!isset($item['tab_root']) && !$parent['_tab']) {
02331 $item['tab_root'] = $parent_path;
02332 }
02333
02334
02335
02336 if (($item['type'] == MENU_DEFAULT_LOCAL_TASK) && !isset($item['access callback']) && isset($parent['access callback'])) {
02337 $item['access callback'] = $parent['access callback'];
02338 if (!isset($item['access arguments']) && isset($parent['access arguments'])) {
02339 $item['access arguments'] = $parent['access arguments'];
02340 }
02341 }
02342
02343 if (!isset($item['page callback']) && isset($parent['page callback'])) {
02344 $item['page callback'] = $parent['page callback'];
02345 if (!isset($item['page arguments']) && isset($parent['page arguments'])) {
02346 $item['page arguments'] = $parent['page arguments'];
02347 }
02348 }
02349 }
02350 }
02351 if (!isset($item['access callback']) && isset($item['access arguments'])) {
02352
02353 $item['access callback'] = 'user_access';
02354 }
02355 if (!isset($item['access callback']) || empty($item['page callback'])) {
02356 $item['access callback'] = 0;
02357 }
02358 if (is_bool($item['access callback'])) {
02359 $item['access callback'] = intval($item['access callback']);
02360 }
02361
02362 $item += array(
02363 'access arguments' => array(),
02364 'access callback' => '',
02365 'page arguments' => array(),
02366 'page callback' => '',
02367 'block callback' => '',
02368 'title arguments' => array(),
02369 'title callback' => 't',
02370 'description' => '',
02371 'position' => '',
02372 'tab_parent' => '',
02373 'tab_root' => $path,
02374 'path' => $path,
02375 );
02376
02377 $title_arguments = $item['title arguments'] ? serialize($item['title arguments']) : '';
02378 db_query("INSERT INTO {menu_router}
02379 (path, load_functions, to_arg_functions, access_callback,
02380 access_arguments, page_callback, page_arguments, fit,
02381 number_parts, tab_parent, tab_root,
02382 title, title_callback, title_arguments,
02383 type, block_callback, description, position, weight)
02384 VALUES ('%s', '%s', '%s', '%s',
02385 '%s', '%s', '%s', %d,
02386 %d, '%s', '%s',
02387 '%s', '%s', '%s',
02388 %d, '%s', '%s', '%s', %d)",
02389 $path, $item['load_functions'], $item['to_arg_functions'], $item['access callback'],
02390 serialize($item['access arguments']), $item['page callback'], serialize($item['page arguments']), $item['_fit'],
02391 $item['_number_parts'], $item['tab_parent'], $item['tab_root'],
02392 $item['title'], $item['title callback'], $title_arguments,
02393 $item['type'], $item['block callback'], $item['description'], $item['position'], $item['weight']);
02394 }
02395
02396 $masks = array_keys($masks);
02397 rsort($masks);
02398 variable_set('menu_masks', $masks);
02399 return $menu;
02400 }
02401
02405 function menu_path_is_external($path) {
02406 $colonpos = strpos($path, ':');
02407 return $colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && filter_xss_bad_protocol($path, FALSE) == check_plain($path);
02408 }
02409
02421 function _menu_site_is_offline() {
02422
02423 if (variable_get('site_offline', 0)) {
02424
02425 if (user_access('administer site configuration')) {
02426
02427
02428
02429 if (drupal_get_normal_path($_GET['q']) != 'admin/settings/site-maintenance') {
02430 drupal_set_message(t('Operating in off-line mode.'), 'status', FALSE);
02431 }
02432 }
02433 else {
02434
02435 if (user_is_anonymous()) {
02436 return $_GET['q'] != 'user' && $_GET['q'] != 'user/login';
02437 }
02438
02439 require_once drupal_get_path('module', 'user') . '/user.pages.inc';
02440 user_logout();
02441 }
02442 }
02443 return FALSE;
02444 }
02445
02453 function menu_valid_path($form_item) {
02454 global $menu_admin;
02455 $item = array();
02456 $path = $form_item['link_path'];
02457
02458 $menu_admin = TRUE;
02459 if ($path == '<front>' || menu_path_is_external($path)) {
02460 $item = array('access' => TRUE);
02461 }
02462 elseif (preg_match('/\/\%/', $path)) {
02463
02464 if ($item = db_fetch_array(db_query("SELECT * FROM {menu_router} where path = '%s' ", $path))) {
02465 $item['link_path'] = $form_item['link_path'];
02466 $item['link_title'] = $form_item['link_title'];
02467 $item['external'] = FALSE;
02468 $item['options'] = '';
02469 _menu_link_translate($item);
02470 }
02471 }
02472 else {
02473 $item = menu_get_item($path);
02474 }
02475 $menu_admin = FALSE;
02476 return $item && $item['access'];
02477 }
02478