Index: includes/bootstrap.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v retrieving revision 1.163 diff -u -p -r1.163 bootstrap.inc --- includes/bootstrap.inc 30 Apr 2007 14:37:36 -0000 1.163 +++ includes/bootstrap.inc 5 May 2007 09:14:41 -0000 @@ -535,6 +535,46 @@ function drupal_load($type, $name) { } /** + * Includes a library file provided by a module. This allows + * modules to be broken up into functional components while still + * providing access to its functions to other modules. + * + * @param $module + * The module in which to load this component. + * @param $component + * The non-module part of the name of the function we're trying to load. + * The corresponding library file is the part of the function stub after the + * first underscore. So for example to ensure that the function 'system_admin_theme_settings' + * is available, call drupal_include('system', 'admin_theme_settings'). This function will then + * include system/admin.inc if it exists. + * + * @return + * TRUE if the corresponding file was includable and included successfully, FALSE otherwise. + */ +function drupal_include($module, $component) { + static $files = array(); + + $underscore = strpos($component, '_'); + if ($underscore !== FALSE) { + $include = substr($component, 0, $underscore); + $filename = dirname(drupal_get_filename('module', $module)) . "/$module.$include.inc"; + if (isset($files[$module][$filename])) { + return $files[$module][$filename]; + } + + $files[$module][$filename] = FALSE; + if (file_exists($filename)) { + include_once($filename); + $files[$module][$filename] = TRUE; + } + return $files[$module][$filename]; + } + + return FALSE; +} + + +/** * Set HTTP headers in preparation for a page response. * * Authenticated users are always given a 'no-cache' header, and will Index: includes/form.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/form.inc,v retrieving revision 1.191 diff -u -p -r1.191 form.inc --- includes/form.inc 4 May 2007 09:41:36 -0000 1.191 +++ includes/form.inc 5 May 2007 09:14:41 -0000 @@ -202,19 +202,35 @@ function drupal_retrieve_form($form_id) // So, we call the hook if $forms isn't yet populated, OR if it doesn't // yet have an entry for the requested form_id. if (!isset($forms) || !isset($forms[$form_id])) { - $forms = module_invoke_all('forms', $saved_args); + $forms = array(); + // We need to manually call each module so that we can know which module a given form came from. + foreach (module_implements('forms') as $module) { + $module_forms = call_user_func_array($module . '_forms', $saved_args); + if (isset($module_forms) && is_array($module_forms)) { + foreach (array_keys($module_forms) as $form) { + $module_forms[$form]['module'] = $module; + } + //dpr($module_forms); + $forms = array_merge($forms, $module_forms); + } + } } $form_definition = $forms[$form_id]; if (isset($form_definition['callback arguments'])) { $args = array_merge($form_definition['callback arguments'], $args); } - if (isset($form_definition['callback'])) { - $callback = $form_definition['callback']; + + // If 'callback' was returned by a hook_forms() implementation, use that as the callback. + // Otherwise, use the function named after the form id. + $callback = isset($form_definition['callback']) ? $form_definition['callback'] : $form_id; + + // There may be a file that needs to be included. + if (strpos($callback, $form_definition['module']) === 0) { + drupal_include($form_definition['module'], substr($callback, strlen($form_definition['module'])+1)); } } - // If $callback was returned by a hook_forms() implementation, call it. - // Otherwise, call the function named after the form id. - $form = call_user_func_array(isset($callback) ? $callback : $form_id, $args); + + $form = call_user_func_array($callback, $args); // We store the original function arguments, rather than the final $arg // value, so that form_alter functions can see what was originally Index: includes/menu.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/menu.inc,v retrieving revision 1.164 diff -u -p -r1.164 menu.inc --- includes/menu.inc 30 Apr 2007 17:03:22 -0000 1.164 +++ includes/menu.inc 5 May 2007 09:14:42 -0000 @@ -343,7 +343,15 @@ function menu_get_item($path = NULL, $it */ function menu_execute_active_handler() { if ($item = menu_get_item()) { - return $item->access ? call_user_func_array($item->page_callback, $item->page_arguments) : MENU_ACCESS_DENIED; + if (!$item->access) { + return MENU_ACCESS_DENIED; + } + $include = $item->page_callback; + if (strpos($include, $item->module) === 0) { + $include = substr($include, strlen($item->module)+1); + } + drupal_include($item->module, $include); + return call_user_func_array($item->page_callback, $item->page_arguments); } return MENU_NOT_FOUND; } @@ -626,7 +634,22 @@ function menu_path_is_external($path) { */ function menu_rebuild() { // TODO: split menu and menu links storage. - $menu = module_invoke_all('menu'); + + // We need to manually call each module so that we can know which module a given item came from. + // If a given menu item doesn't specify what module its callback lives in, assume it's the + // defining module. + $menu = array(); + foreach (module_implements('menu') as $module) { + $items = call_user_func($module . '_menu'); + if (isset($items) && is_array($items)) { + foreach (array_keys($items) as $path) { + if (!isset($items[$path]['module'])) { + $items[$path]['module'] = $module; + } + } + $menu = array_merge($menu, $items); + } + } // Alter the menu as defined in modules, keys are like user/%user. drupal_alter('menu', $menu, MENU_ALTER_MODULE_DEFINED); @@ -887,10 +910,10 @@ function menu_rebuild() { title_callback, title_arguments, fit, number_parts, visible, parents, depth, has_children, tab, title, parent, type, mleft, mright, block_callback, description, position, - link_path, attributes, query, fragment, absolute, html) + link_path, attributes, query, fragment, absolute, html, module) VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', %d, %d, %d, '%s', '%s', '%s', %d, %d, '%s', '%s', - '%s', '%s', '%s', '%s', '%s', %d, %d)", + '%s', '%s', '%s', '%s', '%s', %d, %d, '%s')", $item['_mid'], $item['_pid'], $path, $item['load_functions'], $item['to_arg_functions'], $item['access callback'], serialize($item['access arguments']), $item['page callback'], @@ -902,7 +925,7 @@ function menu_rebuild() { $item['_mright'], $item['block callback'], $item['description'], $item['position'], $link_path, $item['attributes'], $item['query'], $item['fragment'], - $item['absolute'], $item['html']); + $item['absolute'], $item['html'], $item['module']); } } Index: includes/module.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/module.inc,v retrieving revision 1.100 diff -u -p -r1.100 module.inc --- includes/module.inc 17 Apr 2007 07:19:38 -0000 1.100 +++ includes/module.inc 5 May 2007 09:14:42 -0000 @@ -345,6 +345,7 @@ function module_invoke() { $module = array_shift($args); $hook = array_shift($args); $function = $module .'_'. $hook; + drupal_include($module, $hook); if (module_hook($module, $hook)) { return call_user_func_array($function, $args); } @@ -366,6 +367,7 @@ function module_invoke_all() { $return = array(); foreach (module_implements($hook) as $module) { $function = $module .'_'. $hook; + drupal_include($module, $hook); $result = call_user_func_array($function, $args); if (isset($result) && is_array($result)) { $return = array_merge($return, $result); Index: modules/node/node.module =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.module,v retrieving revision 1.806 diff -u -p -r1.806 node.module --- modules/node/node.module 30 Apr 2007 17:03:26 -0000 1.806 +++ modules/node/node.module 5 May 2007 09:14:42 -0000 @@ -1128,6 +1128,7 @@ function node_menu() { 'weight' => -10, 'page callback' => 'system_admin_menu_block_page', 'access arguments' => array('administer site configuration'), + 'module' => 'system', ); $items['admin/content/node'] = array( Index: modules/system/system.admin.inc =================================================================== RCS file: modules/system/system.admin.inc diff -N modules/system/system.admin.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/system/system.admin.inc 5 May 2007 09:14:42 -0000 @@ -0,0 +1,128 @@ +status report for more information.', array('@status' => url('admin/logs/status'))), 'error'); + } + + $map = arg(NULL); + $result = db_query("SELECT * FROM {menu} WHERE path LIKE 'admin/%%' AND depth = 2 AND visible = 1 AND path != 'admin/help' ORDER BY mleft"); + while ($item = db_fetch_object($result)) { + _menu_translate($item, $map, MENU_RENDER_LINK); + if (!$item->access) { + continue; + } + $block = (array)$item; + $block['content'] = ''; + if ($item->block_callback && function_exists($item->block_callback)) { + $function = $item->block_callback; + $block['content'] .= $function(); + } + $block['content'] .= theme('admin_block_content', system_admin_menu_block($item)); + $blocks[] = $block; + } + return theme('admin_page', $blocks); +} + +function system_admin_compact_page($mode = 'off') { + global $user; + user_save($user, array('admin_compact_mode' => ($mode == 'on'))); + drupal_goto('admin'); +} + +/** + * Menu callback; prints a listing of admin tasks for each installed module. + */ +function system_admin_by_module() { + return 'This page awaits rewrite'; // TODO: this needs to be rewritten for the new menu system. + $modules = module_rebuild_cache(); + $menu_items = array(); + foreach ($modules as $file) { + $module = $file->name; + if ($module == 'help') { + continue; + } + + $admin_tasks = system_get_module_admin_tasks($module); + + // Only display a section if there are any available tasks. + if (count($admin_tasks)) { + + // Check for help links. + if (module_invoke($module, 'help', "admin/help#$module")) { + $admin_tasks[100] = l(t('Get help'), "admin/help/$module"); + } + + // Sort. + ksort($admin_tasks); + + $menu_items[$file->info['name']] = array($file->info['description'], $admin_tasks); + } + } + return theme('system_admin_by_module', $menu_items); +} + +/** + * This function allows selection of the theme to show in administration sections. + */ +function system_admin_theme_settings() { + $themes = system_theme_data(); + ksort($themes); + $options[0] = t('System default'); + foreach ($themes as $theme) { + $options[$theme->name] = $theme->info['name']; + } + + $form['admin_theme'] = array( + '#type' => 'select', + '#options' => $options, + '#title' => t('Administration theme'), + '#description' => t('Choose which theme the administration pages should display in. If you choose "System default" the administration pages will use the same theme as the rest of the site.'), + '#default_value' => variable_get('admin_theme', '0'), + ); + + // In order to give it our own submit, we have to give it the default submit + // too because the presence of a #submit will prevent the default #submit + // from being used. Also we want ours first. + $form['#submit']['system_admin_theme_submit'] = array(); + $form['#submit']['system_settings_form_submit'] = array(); + return system_settings_form($form); +} + + +function system_admin_theme_submit($form_id, $form_values) { + // If we're changing themes, make sure the theme has its blocks initialized. + if ($form_values['admin_theme'] != variable_get('admin_theme', '0')) { + $result = db_query("SELECT status FROM {blocks} WHERE theme = '%s'", $form_values['admin_theme']); + if (!db_num_rows($result)) { + system_initialize_theme_blocks($form_values['admin_theme']); + } + } +} + +/** + * Provide a single block from the administration menu as a page. + * This function is often a destination for these blocks. + * For example, 'admin/content/types' needs to have a destination to be valid + * in the Drupal menu system, but too much information there might be + * hidden, so we supply the contents of the block. + */ +function system_admin_menu_block_page() { + $item = menu_get_item(); + $content = system_admin_menu_block($item); + + $output = theme('admin_block_content', $content); + return $output; +} Index: modules/system/system.install =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.install,v retrieving revision 1.100 diff -u -p -r1.100 system.install --- modules/system/system.install 4 May 2007 09:41:36 -0000 1.100 +++ modules/system/system.install 5 May 2007 09:14:43 -0000 @@ -368,6 +368,7 @@ function system_install() { fragment varchar(255) NOT NULL default '', absolute INT NOT NULL default 0, html INT NOT NULL default 0, + module varchar(255) NOT NULL default '', PRIMARY KEY (path), KEY fit (fit), KEY visible (visible), @@ -853,6 +854,7 @@ function system_install() { fragment varchar(255) NOT NULL default '', absolute INT NOT NULL default 0, html INT NOT NULL default 0, + module varchar(255) NOT NULL default '', PRIMARY KEY (path) )"); @@ -3865,6 +3867,25 @@ function system_update_6012() { } /** + * Add module column to menu table + */ +function system_update_6013() { + $ret = array(); + + switch ($GLOBALS['db_type']) { + case 'pgsql': + db_add_column($ret, 'menu', 'module', 'varchar(255)', array('default' => "''", 'not null' => TRUE)); + break; + case 'mysql': + case 'mysqli': + $ret[] = update_sql("ALTER TABLE {menu} ADD module varchar(255) NOT NULL default ''"); + break; + } + + return $ret; +} + +/** * @} End of "defgroup updates-5.x-to-6.x" * The next series of updates should start at 7000. */ Index: modules/system/system.module =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.module,v retrieving revision 1.473 diff -u -p -r1.473 system.module --- modules/system/system.module 4 May 2007 09:41:37 -0000 1.473 +++ modules/system/system.module 5 May 2007 09:14:43 -0000 @@ -119,6 +119,11 @@ function system_elements() { return $type; } +function system_forms() { + $forms['system_admin_theme_settings'] = array(); + return $forms; +} + /** * Implementation of hook_menu(). */ @@ -132,7 +137,7 @@ function system_menu() { $items['admin'] = array( 'title' => 'Administer', 'access arguments' => array('access administration pages'), - 'page callback' => 'system_main_admin_page', + 'page callback' => 'system_admin_main_page', 'weight' => 9, ); $items['admin/compact'] = array( @@ -142,7 +147,7 @@ function system_menu() { ); $items['admin/by-task'] = array( 'title' => 'By task', - 'page callback' => 'system_main_admin_page', + 'page callback' => 'system_admin_main_page', 'type' => MENU_DEFAULT_LOCAL_TASK, ); $items['admin/by-module'] = array( @@ -380,41 +385,6 @@ function system_user($type, $edit, &$use } /** - * Provide the administration overview page. - */ -function system_main_admin_page($arg = NULL) { - // If we received an argument, they probably meant some other page. - // Let's 404 them since the menu system cannot be told we do not - // accept arguments. - if (isset($arg) && substr($arg, 0, 3) != 'by-') { - return drupal_not_found(); - } - - // Check for status report errors. - if (system_status(TRUE)) { - drupal_set_message(t('One or more problems were detected with your Drupal installation. Check the status report for more information.', array('@status' => url('admin/logs/status'))), 'error'); - } - - $map = arg(NULL); - $result = db_query("SELECT * FROM {menu} WHERE path LIKE 'admin/%%' AND depth = 2 AND visible = 1 AND path != 'admin/help' ORDER BY mleft"); - while ($item = db_fetch_object($result)) { - _menu_translate($item, $map, MENU_RENDER_LINK); - if (!$item->access) { - continue; - } - $block = (array)$item; - $block['content'] = ''; - if ($item->block_callback && function_exists($item->block_callback)) { - $function = $item->block_callback; - $block['content'] .= $function(); - } - $block['content'] .= theme('admin_block_content', system_admin_menu_block($item)); - $blocks[] = $block; - } - return theme('admin_page', $blocks); -} - -/** * Provide a single block on the administration overview page. */ function system_admin_menu_block($item) { @@ -431,65 +401,6 @@ function system_admin_menu_block($item) return $content; } -/** - * Provide a single block from the administration menu as a page. - * This function is often a destination for these blocks. - * For example, 'admin/content/types' needs to have a destination to be valid - * in the Drupal menu system, but too much information there might be - * hidden, so we supply the contents of the block. - */ -function system_admin_menu_block_page() { - $item = menu_get_item(); - $content = system_admin_menu_block($item); - - $output = theme('admin_block_content', $content); - return $output; -} - -function system_admin_compact_page($mode = 'off') { - global $user; - user_save($user, array('admin_compact_mode' => ($mode == 'on'))); - drupal_goto('admin'); -} - -/** - * This function allows selection of the theme to show in administration sections. - */ -function system_admin_theme_settings() { - $themes = system_theme_data(); - ksort($themes); - $options[0] = t('System default'); - foreach ($themes as $theme) { - $options[$theme->name] = $theme->info['name']; - } - - $form['admin_theme'] = array( - '#type' => 'select', - '#options' => $options, - '#title' => t('Administration theme'), - '#description' => t('Choose which theme the administration pages should display in. If you choose "System default" the administration pages will use the same theme as the rest of the site.'), - '#default_value' => variable_get('admin_theme', '0'), - ); - - // In order to give it our own submit, we have to give it the default submit - // too because the presence of a #submit will prevent the default #submit - // from being used. Also we want ours first. - $form['#submit']['system_admin_theme_submit'] = array(); - $form['#submit']['system_settings_form_submit'] = array(); - return system_settings_form($form); -} - - -function system_admin_theme_submit($form_id, $form_values) { - // If we're changing themes, make sure the theme has its blocks initialized. - if ($form_values['admin_theme'] != variable_get('admin_theme', '0')) { - $result = db_query("SELECT status FROM {blocks} WHERE theme = '%s'", $form_values['admin_theme']); - if (!db_num_rows($result)) { - system_initialize_theme_blocks($form_values['admin_theme']); - } - } -} - /* * Returns a fieldset containing the theme select form. * @@ -2360,38 +2271,6 @@ function theme_admin_block_content($cont return $output; } -/** - * Menu callback; prints a listing of admin tasks for each installed module. - */ -function system_admin_by_module() { - return 'This page awaits rewrite'; // TODO: this needs to be rewritten for the new menu system. - $modules = module_rebuild_cache(); - $menu_items = array(); - foreach ($modules as $file) { - $module = $file->name; - if ($module == 'help') { - continue; - } - - $admin_tasks = system_get_module_admin_tasks($module); - - // Only display a section if there are any available tasks. - if (count($admin_tasks)) { - - // Check for help links. - if (module_invoke($module, 'help', "admin/help#$module")) { - $admin_tasks[100] = l(t('Get help'), "admin/help/$module"); - } - - // Sort. - ksort($admin_tasks); - - $menu_items[$file->info['name']] = array($file->info['description'], $admin_tasks); - } - } - return theme('system_admin_by_module', $menu_items); -} - function system_get_module_admin_tasks($module) { return array(); // TODO: this needs to be rewritten for the new menu system. $admin_access = user_access('administer access control'); k