Merge lp:~pressflow/pressflow/menu-tng into lp:pressflow
- menu-tng
- Merge into 6
Proposed by
David Strauss
Status: | Rejected |
---|---|
Rejected by: | David Strauss |
Proposed branch: | lp:~pressflow/pressflow/menu-tng |
Merge into: | lp:pressflow |
Diff against target: |
538 lines (+304/-52) 2 files modified
includes/menu.inc (+302/-50) modules/book/book.module (+2/-2) |
To merge this branch: | bzr merge lp:~pressflow/pressflow/menu-tng |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Pressflow Administrators | Pending | ||
Review via email: mp+15439@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Unmerged revisions
- 65. By David Strauss
-
Initial (seemingly working) Menu-TNG system.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'includes/menu.inc' | |||
2 | --- includes/menu.inc 2009-04-30 00:36:53 +0000 | |||
3 | +++ includes/menu.inc 2009-11-30 19:05:26 +0000 | |||
4 | @@ -285,7 +285,7 @@ | |||
5 | 285 | } | 285 | } |
6 | 286 | 286 | ||
7 | 287 | /** | 287 | /** |
9 | 288 | * Get a router item. | 288 | * Get a router item. Pressflow-optimized. |
10 | 289 | * | 289 | * |
11 | 290 | * @param $path | 290 | * @param $path |
12 | 291 | * The path, for example node/5. The function will find the corresponding | 291 | * The path, for example node/5. The function will find the corresponding |
13 | @@ -293,13 +293,14 @@ | |||
14 | 293 | * @param $router_item | 293 | * @param $router_item |
15 | 294 | * Internal use only. | 294 | * Internal use only. |
16 | 295 | * @return | 295 | * @return |
22 | 296 | * The router item, an associate array corresponding to one row in the | 296 | * The router item, an associative array corresponding to one menu item. |
23 | 297 | * menu_router table. The value of key map holds the loaded objects. The | 297 | * The value of key map holds the loaded objects. The value of key access |
24 | 298 | * value of key access is TRUE if the current user can access this page. | 298 | * is TRUE if the current user can access this page. |
20 | 299 | * The values for key title, page_arguments, access_arguments will be | ||
21 | 300 | * filled in based on the database values and the objects loaded. | ||
25 | 301 | */ | 299 | */ |
26 | 302 | function menu_get_item($path = NULL, $router_item = NULL) { | 300 | function menu_get_item($path = NULL, $router_item = NULL) { |
27 | 301 | static $tree = NULL; | ||
28 | 302 | |||
29 | 303 | $start = microtime(TRUE); | ||
30 | 303 | static $router_items; | 304 | static $router_items; |
31 | 304 | if (!isset($path)) { | 305 | if (!isset($path)) { |
32 | 305 | $path = $_GET['q']; | 306 | $path = $_GET['q']; |
33 | @@ -310,28 +311,63 @@ | |||
34 | 310 | if (!isset($router_items[$path])) { | 311 | if (!isset($router_items[$path])) { |
35 | 311 | $original_map = arg(NULL, $path); | 312 | $original_map = arg(NULL, $path); |
36 | 312 | $parts = array_slice($original_map, 0, MENU_MAX_PARTS); | 313 | $parts = array_slice($original_map, 0, MENU_MAX_PARTS); |
42 | 313 | list($ancestors, $placeholders) = menu_get_ancestors($parts); | 314 | |
43 | 314 | 315 | if (!$tree) { | |
44 | 315 | 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))) { | 316 | $tree = menu_get_tree(); |
45 | 316 | $map = _menu_translate($router_item, $original_map); | 317 | } |
46 | 317 | if ($map === FALSE) { | 318 | $cursor =& $tree; |
47 | 319 | |||
48 | 320 | foreach ($parts as $element) { | ||
49 | 321 | // Try the best fit first. | ||
50 | 322 | if (isset($cursor[$element])) { | ||
51 | 323 | $cursor =& $cursor[$element]; | ||
52 | 324 | } | ||
53 | 325 | // Then try a placeholder fit. | ||
54 | 326 | else if (isset($cursor['%'])) { | ||
55 | 327 | $cursor =& $cursor['%']; | ||
56 | 328 | } | ||
57 | 329 | // Check if there's a leaf available. | ||
58 | 330 | else if (isset($cursor['#leaf'])) { | ||
59 | 331 | break; | ||
60 | 332 | } | ||
61 | 333 | // If there's no fit, there's no matching item. | ||
62 | 334 | else { | ||
63 | 318 | $router_items[$path] = FALSE; | 335 | $router_items[$path] = FALSE; |
64 | 319 | return FALSE; | 336 | return FALSE; |
65 | 320 | } | 337 | } |
71 | 321 | if ($router_item['access']) { | 338 | } |
72 | 322 | $router_item['map'] = $map; | 339 | |
73 | 323 | $router_item['page_arguments'] = array_merge(menu_unserialize($router_item['page_arguments'], $map), array_slice($map, $router_item['number_parts'])); | 340 | // At this point, there should be a leaf. |
74 | 324 | } | 341 | if (!isset($cursor['#leaf'])) { |
75 | 325 | } | 342 | $router_items[$path] = FALSE; |
76 | 343 | return FALSE; | ||
77 | 344 | } | ||
78 | 345 | |||
79 | 346 | $router_item = $cursor['#leaf']; | ||
80 | 347 | |||
81 | 348 | //echo "router_item:\n"; | ||
82 | 349 | //print_r($router_item); | ||
83 | 350 | |||
84 | 351 | $map = _menu_translate($router_item, $original_map); | ||
85 | 352 | if ($map === FALSE) { | ||
86 | 353 | $router_items[$path] = FALSE; | ||
87 | 354 | return FALSE; | ||
88 | 355 | } | ||
89 | 356 | if ($router_item['access']) { | ||
90 | 357 | $router_item['map'] = $map; | ||
91 | 358 | $router_item['page_arguments'] = array_merge(menu_unserialize($router_item['page_arguments'], $map), array_slice($map, $router_item['number_parts'])); | ||
92 | 359 | } | ||
93 | 360 | |||
94 | 326 | $router_items[$path] = $router_item; | 361 | $router_items[$path] = $router_item; |
95 | 327 | } | 362 | } |
96 | 363 | header('X-Profile-' . str_replace('/', '-', $path) . ': ' . number_format(microtime(TRUE) - $start, 10)); | ||
97 | 328 | return $router_items[$path]; | 364 | return $router_items[$path]; |
98 | 329 | } | 365 | } |
99 | 330 | 366 | ||
100 | 331 | /** | 367 | /** |
101 | 332 | * Execute the page callback associated with the current path | 368 | * Execute the page callback associated with the current path |
102 | 333 | */ | 369 | */ |
104 | 334 | function menu_execute_active_handler($path = NULL) { | 370 | function menu_execute_active_handler($path = NULL, $old = FALSE) { |
105 | 335 | if (_menu_site_is_offline()) { | 371 | if (_menu_site_is_offline()) { |
106 | 336 | return MENU_SITE_OFFLINE; | 372 | return MENU_SITE_OFFLINE; |
107 | 337 | } | 373 | } |
108 | @@ -340,7 +376,8 @@ | |||
109 | 340 | if (variable_get('menu_rebuild_needed', FALSE) || !variable_get('menu_masks', array())) { | 376 | if (variable_get('menu_rebuild_needed', FALSE) || !variable_get('menu_masks', array())) { |
110 | 341 | menu_rebuild(); | 377 | menu_rebuild(); |
111 | 342 | } | 378 | } |
113 | 343 | if ($router_item = menu_get_item($path)) { | 379 | |
114 | 380 | if ((!$old && $router_item = menu_get_item($path)) || ($old && $router_item = menu_get_item_old($path))) { | ||
115 | 344 | if ($router_item['access']) { | 381 | if ($router_item['access']) { |
116 | 345 | if ($router_item['file']) { | 382 | if ($router_item['file']) { |
117 | 346 | require_once($router_item['file']); | 383 | require_once($router_item['file']); |
118 | @@ -434,6 +471,7 @@ | |||
119 | 434 | * $item['access'] becomes TRUE if the item is accessible, FALSE otherwise. | 471 | * $item['access'] becomes TRUE if the item is accessible, FALSE otherwise. |
120 | 435 | */ | 472 | */ |
121 | 436 | function _menu_check_access(&$item, $map) { | 473 | function _menu_check_access(&$item, $map) { |
122 | 474 | //print_r($item); | ||
123 | 437 | // Determine access callback, which will decide whether or not the current | 475 | // Determine access callback, which will decide whether or not the current |
124 | 438 | // user has access to this path. | 476 | // user has access to this path. |
125 | 439 | $callback = empty($item['access_callback']) ? 0 : trim($item['access_callback']); | 477 | $callback = empty($item['access_callback']) ? 0 : trim($item['access_callback']); |
126 | @@ -443,6 +481,9 @@ | |||
127 | 443 | } | 481 | } |
128 | 444 | else { | 482 | else { |
129 | 445 | $arguments = menu_unserialize($item['access_arguments'], $map); | 483 | $arguments = menu_unserialize($item['access_arguments'], $map); |
130 | 484 | |||
131 | 485 | //print_r($arguments); | ||
132 | 486 | |||
133 | 446 | // As call_user_func_array is quite slow and user_access is a very common | 487 | // As call_user_func_array is quite slow and user_access is a very common |
134 | 447 | // callback, it is worth making a special case for it. | 488 | // callback, it is worth making a special case for it. |
135 | 448 | if ($callback == 'user_access') { | 489 | if ($callback == 'user_access') { |
136 | @@ -823,12 +864,11 @@ | |||
137 | 823 | $parents = array(); | 864 | $parents = array(); |
138 | 824 | } | 865 | } |
139 | 825 | array_unshift($args, $menu_name); | 866 | array_unshift($args, $menu_name); |
143 | 826 | // Select the links from the table, and recursively build the tree. We | 867 | // Select the links from the table, and recursively build the tree. Loading data for |
144 | 827 | // LEFT JOIN since there is no match in {menu_router} for an external | 868 | // internal links (formerly from {menu_router}) has moved to _menu_tree_data() in Pressflow. |
142 | 828 | // link. | ||
145 | 829 | $data['tree'] = menu_tree_data(db_query(" | 869 | $data['tree'] = menu_tree_data(db_query(" |
148 | 830 | 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.* | 870 | SELECT ml.* |
149 | 831 | FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path | 871 | FROM {menu_links} ml |
150 | 832 | WHERE ml.menu_name = '%s'". $where ." | 872 | WHERE ml.menu_name = '%s'". $where ." |
151 | 833 | ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", $args), $parents); | 873 | ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", $args), $parents); |
152 | 834 | $data['node_links'] = array(); | 874 | $data['node_links'] = array(); |
153 | @@ -930,12 +970,10 @@ | |||
154 | 930 | $placeholders = '%d'; | 970 | $placeholders = '%d'; |
155 | 931 | $parents = array(); | 971 | $parents = array(); |
156 | 932 | } | 972 | } |
160 | 933 | // Select the links from the table, and recursively build the tree. We | 973 | // Select the links from the table, and recursively build the tree. |
158 | 934 | // LEFT JOIN since there is no match in {menu_router} for an external | ||
159 | 935 | // link. | ||
161 | 936 | $data['tree'] = menu_tree_data(db_query(" | 974 | $data['tree'] = menu_tree_data(db_query(" |
164 | 937 | 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.* | 975 | SELECT ml.* |
165 | 938 | FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path | 976 | FROM {menu_links} ml |
166 | 939 | WHERE ml.menu_name = '%s' AND ml.plid IN (". $placeholders .") | 977 | WHERE ml.menu_name = '%s' AND ml.plid IN (". $placeholders .") |
167 | 940 | ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", $args), $parents); | 978 | ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", $args), $parents); |
168 | 941 | $data['node_links'] = array(); | 979 | $data['node_links'] = array(); |
169 | @@ -1067,6 +1105,26 @@ | |||
170 | 1067 | $remnant = NULL; | 1105 | $remnant = NULL; |
171 | 1068 | $tree = array(); | 1106 | $tree = array(); |
172 | 1069 | while ($item = db_fetch_array($result)) { | 1107 | while ($item = db_fetch_array($result)) { |
173 | 1108 | |||
174 | 1109 | // Load additional data for the menu item. | ||
175 | 1110 | $menu_item = menu_get_item($item['router_path']); | ||
176 | 1111 | if ($menu_item) { | ||
177 | 1112 | $menu_item_filter_keys = array( | ||
178 | 1113 | 'load_functions', | ||
179 | 1114 | 'to_arg_functions', | ||
180 | 1115 | 'access_callback', | ||
181 | 1116 | 'access_arguments', | ||
182 | 1117 | 'page_callback', | ||
183 | 1118 | 'page_arguments', | ||
184 | 1119 | 'title', | ||
185 | 1120 | 'title_callback', | ||
186 | 1121 | 'title_arguments', | ||
187 | 1122 | 'type', | ||
188 | 1123 | 'description', | ||
189 | 1124 | ); | ||
190 | 1125 | $item += array_intersect_key($menu_item, array_fill_keys($menu_item_filter_keys, TRUE)); | ||
191 | 1126 | } | ||
192 | 1127 | |||
193 | 1070 | // We need to determine if we're on the path to root so we can later build | 1128 | // We need to determine if we're on the path to root so we can later build |
194 | 1071 | // the correct active trail and breadcrumb. | 1129 | // the correct active trail and breadcrumb. |
195 | 1072 | $item['in_active_trail'] = in_array($item['mlid'], $parents); | 1130 | $item['in_active_trail'] = in_array($item['mlid'], $parents); |
196 | @@ -1297,6 +1355,14 @@ | |||
197 | 1297 | return $links; | 1355 | return $links; |
198 | 1298 | } | 1356 | } |
199 | 1299 | 1357 | ||
200 | 1358 | function _menu_sort_callback($item1, $item2) { | ||
201 | 1359 | if ($item1['weight'] != $item2['weight']) { | ||
202 | 1360 | return ($item1['weight'] < $item2['weight']) ? -1 : 1; | ||
203 | 1361 | } | ||
204 | 1362 | |||
205 | 1363 | return ($item1['title'] < $item2['title']) ? -1 : 1; | ||
206 | 1364 | } | ||
207 | 1365 | |||
208 | 1300 | /** | 1366 | /** |
209 | 1301 | * Collects the local tasks (tabs) for a given level. | 1367 | * Collects the local tasks (tabs) for a given level. |
210 | 1302 | * | 1368 | * |
211 | @@ -1321,13 +1387,34 @@ | |||
212 | 1321 | return ''; | 1387 | return ''; |
213 | 1322 | } | 1388 | } |
214 | 1323 | // Get all tabs and the root page. | 1389 | // Get all tabs and the root page. |
216 | 1324 | $result = db_query("SELECT * FROM {menu_router} WHERE tab_root = '%s' ORDER BY weight, title", $router_item['tab_root']); | 1390 | $menu_tree =& menu_get_tree(); |
217 | 1391 | $items = array(); | ||
218 | 1392 | $cursor =& $menu_tree; | ||
219 | 1393 | $parts = explode('/', $router_item['tab_root']); | ||
220 | 1394 | foreach ($parts as $part) { | ||
221 | 1395 | if (isset($cursor[$part])) { | ||
222 | 1396 | $cursor = $cursor[$part]; | ||
223 | 1397 | } | ||
224 | 1398 | else if (isset($cursor['%'])) { | ||
225 | 1399 | $cursor = $cursor['%']; | ||
226 | 1400 | } | ||
227 | 1401 | else { | ||
228 | 1402 | $cursor = array(); | ||
229 | 1403 | } | ||
230 | 1404 | } | ||
231 | 1405 | foreach ($cursor as $key => $item) { | ||
232 | 1406 | if ($key != '#leaf') { | ||
233 | 1407 | $items[] = $item; | ||
234 | 1408 | } | ||
235 | 1409 | } | ||
236 | 1410 | usort($items, '_menu_sort_callback'); | ||
237 | 1411 | |||
238 | 1325 | $map = arg(); | 1412 | $map = arg(); |
239 | 1326 | $children = array(); | 1413 | $children = array(); |
240 | 1327 | $tasks = array(); | 1414 | $tasks = array(); |
241 | 1328 | $root_path = $router_item['path']; | 1415 | $root_path = $router_item['path']; |
242 | 1329 | 1416 | ||
244 | 1330 | while ($item = db_fetch_array($result)) { | 1417 | foreach ($items as $item) { |
245 | 1331 | _menu_translate($item, $map, TRUE); | 1418 | _menu_translate($item, $map, TRUE); |
246 | 1332 | if ($item['tab_parent']) { | 1419 | if ($item['tab_parent']) { |
247 | 1333 | // All tabs, but not the root page. | 1420 | // All tabs, but not the root page. |
248 | @@ -1627,7 +1714,11 @@ | |||
249 | 1627 | * rendering. | 1714 | * rendering. |
250 | 1628 | */ | 1715 | */ |
251 | 1629 | function menu_link_load($mlid) { | 1716 | function menu_link_load($mlid) { |
253 | 1630 | 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))) { | 1717 | if (is_numeric($mlid) && $item = db_fetch_array(db_query("SELECT ml.* FROM {menu_links} ml WHERE ml.mlid = %d", $mlid))) { |
254 | 1718 | $menu_item = menu_get_item($item['router_path']); | ||
255 | 1719 | if ($menu_item) { | ||
256 | 1720 | $item += $menu_item; | ||
257 | 1721 | } | ||
258 | 1631 | _menu_link_translate($item); | 1722 | _menu_link_translate($item); |
259 | 1632 | return $item; | 1723 | return $item; |
260 | 1633 | } | 1724 | } |
261 | @@ -1648,6 +1739,7 @@ | |||
262 | 1648 | register_shutdown_function('cache_clear_all', 'links:'. $menu_name .':', 'cache_menu', TRUE); | 1739 | register_shutdown_function('cache_clear_all', 'links:'. $menu_name .':', 'cache_menu', TRUE); |
263 | 1649 | $cache_cleared[$menu_name] = 2; | 1740 | $cache_cleared[$menu_name] = 2; |
264 | 1650 | } | 1741 | } |
265 | 1742 | menu_rebuild(); | ||
266 | 1651 | } | 1743 | } |
267 | 1652 | 1744 | ||
268 | 1653 | /** | 1745 | /** |
269 | @@ -1656,12 +1748,13 @@ | |||
270 | 1656 | */ | 1748 | */ |
271 | 1657 | function menu_cache_clear_all() { | 1749 | function menu_cache_clear_all() { |
272 | 1658 | cache_clear_all('*', 'cache_menu', TRUE); | 1750 | cache_clear_all('*', 'cache_menu', TRUE); |
273 | 1751 | menu_rebuild(); | ||
274 | 1659 | } | 1752 | } |
275 | 1660 | 1753 | ||
276 | 1661 | /** | 1754 | /** |
278 | 1662 | * (Re)populate the database tables used by various menu functions. | 1755 | * (Re)populate the data used by various menu functions. |
279 | 1663 | * | 1756 | * |
281 | 1664 | * This function will clear and populate the {menu_router} table, add entries | 1757 | * This function will clear and populate the menu tree, add entries |
282 | 1665 | * to {menu_links} for new router items, then remove stale items from | 1758 | * to {menu_links} for new router items, then remove stale items from |
283 | 1666 | * {menu_links}. If called from update.php or install.php, it will also | 1759 | * {menu_links}. If called from update.php or install.php, it will also |
284 | 1667 | * schedule a call to itself on the first real page load from | 1760 | * schedule a call to itself on the first real page load from |
285 | @@ -1669,15 +1762,9 @@ | |||
286 | 1669 | * is different and leaves stale data in the menu tables. | 1762 | * is different and leaves stale data in the menu tables. |
287 | 1670 | */ | 1763 | */ |
288 | 1671 | function menu_rebuild() { | 1764 | function menu_rebuild() { |
298 | 1672 | variable_del('menu_rebuild_needed'); | 1765 | // Note the current time of the rebuild request. This timestamp is guaranteed consistent across the cluster. |
299 | 1673 | $menu = menu_router_build(TRUE); | 1766 | // The rebuild request is stored for up to a day. |
300 | 1674 | _menu_navigation_links_rebuild($menu); | 1767 | cache_set('menu_tree_rebuild', $_SERVER['REQUEST_TIME'], 'cache', $_SERVER['REQUEST_TIME'] + 86400); |
292 | 1675 | // Clear the menu, page and block caches. | ||
293 | 1676 | menu_cache_clear_all(); | ||
294 | 1677 | _menu_clear_page_cache(); | ||
295 | 1678 | if (defined('MAINTENANCE_MODE')) { | ||
296 | 1679 | variable_set('menu_rebuild_needed', TRUE); | ||
297 | 1680 | } | ||
301 | 1681 | } | 1768 | } |
302 | 1682 | 1769 | ||
303 | 1683 | /** | 1770 | /** |
304 | @@ -1730,7 +1817,7 @@ | |||
305 | 1730 | $item['hidden'] = 1; | 1817 | $item['hidden'] = 1; |
306 | 1731 | } | 1818 | } |
307 | 1732 | // Note, we set this as 'system', so that we can be sure to distinguish all | 1819 | // Note, we set this as 'system', so that we can be sure to distinguish all |
309 | 1733 | // the menu links generated automatically from entries in {menu_router}. | 1820 | // the menu links generated automatically from entries in the menu tree. |
310 | 1734 | $item['module'] = 'system'; | 1821 | $item['module'] = 'system'; |
311 | 1735 | $item += array( | 1822 | $item += array( |
312 | 1736 | 'menu_name' => 'navigation', | 1823 | 'menu_name' => 'navigation', |
313 | @@ -2056,15 +2143,16 @@ | |||
314 | 2056 | // $menu will only have data during a menu rebuild. | 2143 | // $menu will only have data during a menu rebuild. |
315 | 2057 | $menu = _menu_router_cache(); | 2144 | $menu = _menu_router_cache(); |
316 | 2058 | 2145 | ||
317 | 2059 | $router_path = $link_path; | ||
318 | 2060 | $parts = explode('/', $link_path, MENU_MAX_PARTS); | ||
319 | 2061 | list($ancestors, $placeholders) = menu_get_ancestors($parts); | ||
320 | 2062 | |||
321 | 2063 | if (empty($menu)) { | 2146 | if (empty($menu)) { |
322 | 2064 | // Not during a menu rebuild, so look up in the database. | 2147 | // Not during a menu rebuild, so look up in the database. |
324 | 2065 | $router_path = (string)db_result(db_query_range('SELECT path FROM {menu_router} WHERE path IN ('. implode (',', $placeholders) .') ORDER BY fit DESC', $ancestors, 0, 1)); | 2148 | $menu_item = menu_get_item($link_path); |
325 | 2149 | $router_path = $menu_item['path']; | ||
326 | 2066 | } | 2150 | } |
327 | 2067 | elseif (!isset($menu[$router_path])) { | 2151 | elseif (!isset($menu[$router_path])) { |
328 | 2152 | $router_path = $link_path; | ||
329 | 2153 | $parts = explode('/', $link_path, MENU_MAX_PARTS); | ||
330 | 2154 | list($ancestors, $placeholders) = menu_get_ancestors($parts); | ||
331 | 2155 | |||
332 | 2068 | // Add an empty path as a fallback. | 2156 | // Add an empty path as a fallback. |
333 | 2069 | $ancestors[] = ''; | 2157 | $ancestors[] = ''; |
334 | 2070 | foreach ($ancestors as $key => $router_path) { | 2158 | foreach ($ancestors as $key => $router_path) { |
335 | @@ -2231,7 +2319,7 @@ | |||
336 | 2231 | } | 2319 | } |
337 | 2232 | } | 2320 | } |
338 | 2233 | 2321 | ||
340 | 2234 | /** | 2322 | /** |
341 | 2235 | * Helper function to build the router table based on the data from hook_menu. | 2323 | * Helper function to build the router table based on the data from hook_menu. |
342 | 2236 | */ | 2324 | */ |
343 | 2237 | function _menu_router_build($callbacks) { | 2325 | function _menu_router_build($callbacks) { |
344 | @@ -2492,7 +2580,7 @@ | |||
345 | 2492 | } | 2580 | } |
346 | 2493 | elseif (preg_match('/\/\%/', $path)) { | 2581 | elseif (preg_match('/\/\%/', $path)) { |
347 | 2494 | // Path is dynamic (ie 'user/%'), so check directly against menu_router table. | 2582 | // Path is dynamic (ie 'user/%'), so check directly against menu_router table. |
349 | 2495 | if ($item = db_fetch_array(db_query("SELECT * FROM {menu_router} where path = '%s' ", $path))) { | 2583 | if ($item = menu_get_item($path)) { |
350 | 2496 | $item['link_path'] = $form_item['link_path']; | 2584 | $item['link_path'] = $form_item['link_path']; |
351 | 2497 | $item['link_title'] = $form_item['link_title']; | 2585 | $item['link_title'] = $form_item['link_title']; |
352 | 2498 | $item['external'] = FALSE; | 2586 | $item['external'] = FALSE; |
353 | @@ -2507,6 +2595,170 @@ | |||
354 | 2507 | return $item && $item['access']; | 2595 | return $item && $item['access']; |
355 | 2508 | } | 2596 | } |
356 | 2509 | 2597 | ||
357 | 2598 | /* | ||
358 | 2599 | * Returns a structured array with all menu items. Pressflow-specific. | ||
359 | 2600 | * | ||
360 | 2601 | * @returns A structured array with all menu items. | ||
361 | 2602 | */ | ||
362 | 2603 | function menu_get_tree() { | ||
363 | 2604 | // Attempt to load the tree from cache. | ||
364 | 2605 | $cache_hit = FALSE; | ||
365 | 2606 | $rebuild = FALSE; | ||
366 | 2607 | $write_to_cache = TRUE; | ||
367 | 2608 | if (function_exists('apc_fetch')) { | ||
368 | 2609 | $cache_item = apc_fetch('menu_tree', $cache_hit); | ||
369 | 2610 | |||
370 | 2611 | if ($cache_hit) { | ||
371 | 2612 | // Check if there is a recent rebuild request. | ||
372 | 2613 | $rebuild_request = cache_get('menu_tree_rebuild'); | ||
373 | 2614 | |||
374 | 2615 | // Check if the rebuild request postdates the locally cached menu tree. | ||
375 | 2616 | if ($rebuild_request && $rebuild_request->data > $cache_item->created) { | ||
376 | 2617 | // We need to rebuild the locally cached menu tree. Attempt to grab a semaphore. | ||
377 | 2618 | $rebuild = apc_add('menu_tree_semaphore', TRUE, 86400); | ||
378 | 2619 | |||
379 | 2620 | if (!$rebuild) { | ||
380 | 2621 | // If the semaphore grab was unsuccessful, return the current (slightly stale) menu tree. | ||
381 | 2622 | $tree =& $cache_item->data; | ||
382 | 2623 | } | ||
383 | 2624 | } | ||
384 | 2625 | else { | ||
385 | 2626 | $tree =& $cache_item->data; | ||
386 | 2627 | } | ||
387 | 2628 | |||
388 | 2629 | header('X-APC-Menu-Cache: HIT'); | ||
389 | 2630 | } | ||
390 | 2631 | else { | ||
391 | 2632 | header('X-APC-Menu-Cache: MISS'); | ||
392 | 2633 | } | ||
393 | 2634 | } | ||
394 | 2635 | else { | ||
395 | 2636 | $cache_item = cache_get('menu_tree', 'cache'); | ||
396 | 2637 | if ($cache_item) { | ||
397 | 2638 | $cache_hit = TRUE; | ||
398 | 2639 | $tree = $cache_item->data; | ||
399 | 2640 | } | ||
400 | 2641 | } | ||
401 | 2642 | |||
402 | 2643 | // On miss, rebuild the tree. | ||
403 | 2644 | if (!$cache_hit || $rebuild) { | ||
404 | 2645 | // Build a fresh menu. | ||
405 | 2646 | $menu = menu_router_build(TRUE); | ||
406 | 2647 | |||
407 | 2648 | // Run the rest of the legacy menu_rebuild(). | ||
408 | 2649 | // TODO: Obsolete this code and anything relying on {menu_*} tables. | ||
409 | 2650 | _menu_navigation_links_rebuild($menu); | ||
410 | 2651 | menu_cache_clear_all(); | ||
411 | 2652 | _menu_clear_page_cache(); | ||
412 | 2653 | |||
413 | 2654 | // Return to the Pressflow rebuild. | ||
414 | 2655 | $tree = array(); | ||
415 | 2656 | foreach ($menu as $path => $item) { | ||
416 | 2657 | |||
417 | 2658 | $item = array( | ||
418 | 2659 | 'path' => $item['path'], | ||
419 | 2660 | 'load_functions' => $item['load_functions'], | ||
420 | 2661 | 'to_arg_functions' => $item['to_arg_functions'], | ||
421 | 2662 | 'access_callback' => $item['access callback'], | ||
422 | 2663 | 'access_arguments' => serialize($item['access arguments']), | ||
423 | 2664 | 'page_callback' => $item['page callback'], | ||
424 | 2665 | 'page_arguments' => serialize($item['page arguments']), | ||
425 | 2666 | 'fit' => $item['_fit'], | ||
426 | 2667 | 'number_parts' => count($item['_parts']), | ||
427 | 2668 | 'tab_parent' => $item['tab_parent'], | ||
428 | 2669 | 'tab_root' => $item['tab_root'], | ||
429 | 2670 | 'title' => $item['title'], | ||
430 | 2671 | 'title_callback' => $item['title callback'], | ||
431 | 2672 | 'title_arguments' => $item['title arguments'] ? serialize($item['title arguments']) : '', | ||
432 | 2673 | 'type' => $item['type'], | ||
433 | 2674 | 'block_callback' => $item['block callback'], | ||
434 | 2675 | 'description' => $item['description'], | ||
435 | 2676 | 'position' => $item['position'], | ||
436 | 2677 | 'weight' => $item['weight'], | ||
437 | 2678 | 'file' => $item['include file'], | ||
438 | 2679 | 'href' => $item['href'], | ||
439 | 2680 | 'options' => $item['options'], | ||
440 | 2681 | ); | ||
441 | 2682 | |||
442 | 2683 | $path = explode('/', $path); | ||
443 | 2684 | |||
444 | 2685 | // Ensure the route to the item is initialized. | ||
445 | 2686 | $cursor =& $tree; | ||
446 | 2687 | foreach ($path as $element) { | ||
447 | 2688 | if (!isset($cursor[$element])) { | ||
448 | 2689 | $cursor[$element] = array(); | ||
449 | 2690 | } | ||
450 | 2691 | $cursor =& $cursor[$element]; | ||
451 | 2692 | } | ||
452 | 2693 | |||
453 | 2694 | $cursor['#leaf'] = $item; | ||
454 | 2695 | } | ||
455 | 2696 | |||
456 | 2697 | if ($write_to_cache) { | ||
457 | 2698 | // Use APC if possible. | ||
458 | 2699 | if (function_exists('apc_store')) { | ||
459 | 2700 | $cache_item = new stdClass(); | ||
460 | 2701 | $cache_item->data = $tree; | ||
461 | 2702 | $cache_item->created = $_SERVER['REQUEST_TIME']; | ||
462 | 2703 | |||
463 | 2704 | // TODO: Make the maximum age a variable or constant. | ||
464 | 2705 | apc_store('menu_tree', $cache_item, 86400); | ||
465 | 2706 | header('X-APC-Menu-Cache-Write: DONE'); | ||
466 | 2707 | apc_delete('menu_tree_semaphore'); | ||
467 | 2708 | if (defined('MAINTENANCE_MODE')) { | ||
468 | 2709 | apc_add('menu_tree_rebuild', TRUE); | ||
469 | 2710 | } | ||
470 | 2711 | else { | ||
471 | 2712 | apc_delete('menu_tree_rebuild'); | ||
472 | 2713 | } | ||
473 | 2714 | } | ||
474 | 2715 | // Otherwise use the internal cache. | ||
475 | 2716 | else { | ||
476 | 2717 | cache_set('menu_tree', $tree, 'cache', $_SERVER['REQUEST_TIME'] + 86400); | ||
477 | 2718 | if (defined('MAINTENANCE_MODE')) { | ||
478 | 2719 | cache_set('menu_tree_rebuild', TRUE, 'cache'); | ||
479 | 2720 | } | ||
480 | 2721 | else { | ||
481 | 2722 | cache_clear_all('menu_tree_rebuild', 'cache'); | ||
482 | 2723 | } | ||
483 | 2724 | } | ||
484 | 2725 | } | ||
485 | 2726 | } | ||
486 | 2727 | |||
487 | 2728 | return $tree; | ||
488 | 2729 | } | ||
489 | 2730 | |||
490 | 2731 | function menu_get_item_old($path = NULL, $router_item = NULL) { | ||
491 | 2732 | static $router_items; | ||
492 | 2733 | if (!isset($path)) { | ||
493 | 2734 | $path = $_GET['q']; | ||
494 | 2735 | } | ||
495 | 2736 | if (isset($router_item)) { | ||
496 | 2737 | $router_items[$path] = $router_item; | ||
497 | 2738 | } | ||
498 | 2739 | if (!isset($router_items[$path])) { | ||
499 | 2740 | $original_map = arg(NULL, $path); | ||
500 | 2741 | $parts = array_slice($original_map, 0, MENU_MAX_PARTS); | ||
501 | 2742 | list($ancestors, $placeholders) = menu_get_ancestors($parts); | ||
502 | 2743 | |||
503 | 2744 | 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))) { | ||
504 | 2745 | //echo "old router_item:\n"; | ||
505 | 2746 | //print_r($router_item); | ||
506 | 2747 | $map = _menu_translate($router_item, $original_map); | ||
507 | 2748 | if ($map === FALSE) { | ||
508 | 2749 | $router_items[$path] = FALSE; | ||
509 | 2750 | return FALSE; | ||
510 | 2751 | } | ||
511 | 2752 | if ($router_item['access']) { | ||
512 | 2753 | $router_item['map'] = $map; | ||
513 | 2754 | $router_item['page_arguments'] = array_merge(menu_unserialize($router_item['page_arguments'], $map), array_slice($map, $router_item['number_parts'])); | ||
514 | 2755 | } | ||
515 | 2756 | } | ||
516 | 2757 | $router_items[$path] = $router_item; | ||
517 | 2758 | } | ||
518 | 2759 | return $router_items[$path]; | ||
519 | 2760 | } | ||
520 | 2761 | |||
521 | 2510 | /** | 2762 | /** |
522 | 2511 | * @} End of "defgroup menu". | 2763 | * @} End of "defgroup menu". |
523 | 2512 | */ | 2764 | */ |
524 | 2513 | 2765 | ||
525 | === modified file 'modules/book/book.module' | |||
526 | --- modules/book/book.module 2009-02-25 22:33:09 +0000 | |||
527 | +++ modules/book/book.module 2009-11-30 19:05:26 +0000 | |||
528 | @@ -1068,8 +1068,8 @@ | |||
529 | 1068 | $i++; | 1068 | $i++; |
530 | 1069 | } | 1069 | } |
531 | 1070 | $sql = " | 1070 | $sql = " |
534 | 1071 | 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.* | 1071 | SELECT b.*, ml.* |
535 | 1072 | FROM {menu_links} ml INNER JOIN {menu_router} m ON m.path = ml.router_path | 1072 | FROM {menu_links} ml |
536 | 1073 | INNER JOIN {book} b ON ml.mlid = b.mlid | 1073 | INNER JOIN {book} b ON ml.mlid = b.mlid |
537 | 1074 | WHERE ". implode(' AND ', $match) ." | 1074 | WHERE ". implode(' AND ', $match) ." |
538 | 1075 | ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC"; | 1075 | ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC"; |