From e9f52b4248a5268630b51ee0746dcf8b6449d445 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Hojtsy?= Date: Fri, 30 Nov 2007 12:19:10 +0000 Subject: #141727 by merlinofchaos, dvessel, sun: restore themeability support for maintenance pages (regression) --- includes/bootstrap.inc | 38 ++---- includes/common.inc | 6 +- includes/database.inc | 8 ++ includes/install.inc | 1 - includes/theme.inc | 223 +++++++++-------------------------- includes/theme.maintenance.inc | 258 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 337 insertions(+), 197 deletions(-) create mode 100644 includes/theme.maintenance.inc (limited to 'includes') diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index a8da6fcb2..5345d5926 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -369,7 +369,6 @@ function conf_init() { */ function drupal_get_filename($type, $name, $filename = NULL) { static $files = array(); - global $active_db; if (!isset($files[$type])) { $files[$type] = array(); @@ -385,7 +384,7 @@ function drupal_get_filename($type, $name, $filename = NULL) { // the database. This is required because this function is called both // before we have a database connection (i.e. during installation) and // when a database connection fails. - elseif ($active_db && (($file = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s' AND type = '%s'", $name, $type))) && file_exists($file))) { + elseif (db_is_active() && (($file = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s' AND type = '%s'", $name, $type))) && file_exists($file))) { $files[$type][$name] = $file; } else { @@ -971,35 +970,16 @@ function _drupal_bootstrap($phase) { } /** - * Enables use of the theme system without requiring database access. Since - * there is not database access no theme will be enabled and the default - * themeable functions will be called. Some themeable functions can not be used - * without the full Drupal API loaded. For example, theme_page() is - * unavailable and theme_maintenance_page() must be used in its place. + * Enables use of the theme system without requiring database access. + * + * Loads and initializes the theme system for site installs, updates and when + * the site is in off-line mode. This also applies when the database fails. + * + * @see _drupal_maintenance_theme() */ function drupal_maintenance_theme() { - global $theme; - require_once './includes/path.inc'; - require_once './includes/theme.inc'; - require_once './includes/common.inc'; - require_once './includes/unicode.inc'; - require_once './includes/file.inc'; - require_once './modules/filter/filter.module'; - unicode_check(); - drupal_add_css(drupal_get_path('module', 'system') .'/defaults.css', 'module'); - drupal_add_css(drupal_get_path('module', 'system') .'/system.css', 'module'); - drupal_add_css(drupal_get_path('module', 'system') .'/system-menus.css', 'module'); - $theme = ''; - - // Special case registry of theme functions used by the installer - $themes = drupal_common_themes(); - foreach ($themes as $hook => $info) { - if (!isset($info['file']) && !isset($info['function'])) { - $themes[$hook]['function'] = 'theme_'. $hook; - $themes[$hook]['theme path'] = 'misc'; - } - } - _theme_set_registry($themes); + require_once './includes/theme.maintenance.inc'; + _drupal_maintenance_theme(); } /** diff --git a/includes/common.inc b/includes/common.inc index 6455bdb71..4af694080 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -2865,7 +2865,7 @@ function element_children($element) { /** * Provide theme registration for themes across .inc files. */ -function drupal_common_themes() { +function drupal_common_theme() { return array( // theme.inc 'placeholder' => array( @@ -2876,6 +2876,10 @@ function drupal_common_themes() { 'template' => 'page', ), 'maintenance_page' => array( + 'arguments' => array('content' => NULL, 'show_blocks' => TRUE, 'show_messages' => TRUE), + 'template' => 'maintenance-page', + ), + 'update_page' => array( 'arguments' => array('content' => NULL, 'show_messages' => TRUE), ), 'install_page' => array( diff --git a/includes/database.inc b/includes/database.inc index 63536e036..917fbb830 100644 --- a/includes/database.inc +++ b/includes/database.inc @@ -163,6 +163,14 @@ function db_set_active($name = 'default') { return array_search($previous_db, $db_conns); } +/** + * Returns a boolean depending on the availability of the database. + */ +function db_is_active() { + global $active_db; + return !empty($active_db); +} + /** * Helper function for db_query(). */ diff --git a/includes/install.inc b/includes/install.inc index f034dda85..04f7939b0 100644 --- a/includes/install.inc +++ b/includes/install.inc @@ -615,7 +615,6 @@ function st($string, $args = array()) { } require_once './includes/theme.inc'; - $GLOBALS['theme'] = 'theme'; // Transform arguments before inserting them foreach ($args as $key => $value) { switch ($key[0]) { diff --git a/includes/theme.inc b/includes/theme.inc index 89825dba5..e0e10cafa 100644 --- a/includes/theme.inc +++ b/includes/theme.inc @@ -29,7 +29,7 @@ define('MARK_UPDATED', 2); * Initialize the theme system by loading the theme. */ function init_theme() { - global $theme, $user, $custom_theme, $theme_engine, $theme_key; + global $theme, $user, $custom_theme, $theme_key; // If $theme is already set, assume the others are set, too, and do nothing if (isset($theme)) { @@ -82,8 +82,10 @@ function init_theme() { * the same information as the $theme object. It should be in * 'oldest first' order, meaning the top level of the chain will * be first. + * @param $registry_callback + * The callback to invoke to set the theme registry. */ -function _init_theme($theme, $base_theme = array()) { +function _init_theme($theme, $base_theme = array(), $registry_callback = '_theme_load_registry') { global $theme_info, $base_theme_info, $theme_engine, $theme_path; $theme_info = $theme; $base_theme_info = $base_theme; @@ -174,7 +176,8 @@ function _init_theme($theme, $base_theme = array()) { include_once './'. $theme->owner; } } - _theme_load_registry($theme, $base_theme, $theme_engine); + + $registry_callback($theme, $base_theme, $theme_engine); } /** @@ -394,6 +397,9 @@ function _theme_build_registry($theme, $base_theme, $theme_engine) { /** * Provides a list of currently available themes. * + * If the database is active then it will be retrieved from the database. + * Otherwise it will retrieve a new list. + * * @param $refresh * Whether to reload the list of themes from the database. * @return @@ -408,59 +414,42 @@ function list_themes($refresh = FALSE) { if (empty($list)) { $list = array(); - $result = db_query("SELECT * FROM {system} WHERE type = '%s'", 'theme'); - while ($theme = db_fetch_object($result)) { - if (file_exists($theme->filename)) { - $theme->info = unserialize($theme->info); - foreach ($theme->info['stylesheets'] as $media => $stylesheets) { - foreach ($stylesheets as $stylesheet => $path) { - if (file_exists($path)) { - $theme->stylesheets[$media][$stylesheet] = $path; - } - } + $themes = array(); + // Extract from the database only when it is available. + if (db_is_active()) { + $result = db_query("SELECT * FROM {system} WHERE type = '%s'", 'theme'); + while ($theme = db_fetch_object($result)) { + if (file_exists($theme->filename)) { + $theme->info = unserialize($theme->info); + $themes[] = $theme; } - foreach ($theme->info['scripts'] as $script => $path) { + } + } + else { + // When the database is unavailable, scan the installation. + $themes = _system_theme_data(); + } + + foreach ($themes as $theme) { + foreach ($theme->info['stylesheets'] as $media => $stylesheets) { + foreach ($stylesheets as $stylesheet => $path) { if (file_exists($path)) { - $theme->scripts[$script] = $path; + $theme->stylesheets[$media][$stylesheet] = $path; } } - if (isset($theme->info['engine'])) { - $theme->engine = $theme->info['engine']; - } - if (isset($theme->info['base theme'])) { - $theme->base_theme = $theme->info['base theme']; + } + foreach ($theme->info['scripts'] as $script => $path) { + if (file_exists($path)) { + $theme->scripts[$script] = $path; } - $list[$theme->name] = $theme; } - } - } - - return $list; -} - -/** - * Provides a list of currently available theme engines - * - * @param $refresh - * Whether to reload the list of themes from the database. - * @return - * An array of the currently available theme engines. - */ -function list_theme_engines($refresh = FALSE) { - static $list; - - if ($refresh) { - unset($list); - } - - if (!$list) { - $list = array(); - $result = db_query("SELECT * FROM {system} WHERE type = '%s' AND status = %d ORDER BY name", 'theme_engine', '1'); - while ($engine = db_fetch_object($result)) { - if (file_exists($engine->filename)) { - $engine->info = unserialize($engine->info); - $list[$engine->name] = $engine; + if (isset($theme->info['engine'])) { + $theme->engine = $theme->info['engine']; } + if (isset($theme->info['base theme'])) { + $theme->base_theme = $theme->info['base theme']; + } + $list[$theme->name] = $theme; } } @@ -1028,117 +1017,6 @@ function theme_placeholder($text) { return ''. check_plain($text) .''; } -/** - * Generate a themed maintenance page. - * - * Note: this function is not themeable. - * - * @param $content - * The page content to show. - * @param $show_messages - * Whether to output status and error messages. - * FALSE can be useful to postpone the messages to a subsequent page. - */ -function theme_maintenance_page($content, $show_messages = TRUE) { - // Set required headers. - drupal_set_header('Content-Type: text/html; charset=utf-8'); - drupal_set_html_head(''); - drupal_set_html_head(''); - drupal_set_html_head(''); - drupal_set_html_head(''); - - // Prepare variables. - $variables = array( - 'head_title' => strip_tags(drupal_get_title()), - 'head' => drupal_get_html_head(), - 'styles' => '', - 'scripts' => drupal_get_js(), - 'left' => drupal_get_content('left'), - 'right' => drupal_get_content('right'), - 'base_path' => base_path(), - 'path_to_theme' => base_path() .'themes/garland/minnelli', - 'logo' => base_path() .'themes/garland/minnelli/logo.png', - 'site_title' => t('Drupal'), - 'title' => drupal_get_title(), - 'messages' => $show_messages ? theme('status_messages') : '', - 'content' => $content, - ); - - $output = theme_render_template('misc/maintenance.tpl.php', $variables); - - return $output; -} - -/** - * Generate a themed installation page. - * - * Note: this function is not themeable. - * - * @param $content - * The page content to show. - */ -function theme_install_page($content) { - drupal_set_header('Content-Type: text/html; charset=utf-8'); - drupal_add_css('misc/maintenance.css', 'module', 'all', FALSE); - drupal_set_html_head(''); - - $variables = array( - 'head_title' => strip_tags(drupal_get_title()), - 'head' => drupal_get_html_head(), - 'styles' => drupal_get_css(), - 'scripts' => drupal_get_js(), - 'left' => drupal_get_content('left'), - 'right' => drupal_get_content('right'), - 'base_path' => base_path(), - 'path_to_theme' => base_path() .'themes/garland/minnelli', - 'logo' => base_path() .'themes/garland/minnelli/logo.png', - 'site_title' => st('Drupal Installation'), - 'title' => drupal_get_title(), - 'messages' => '', - 'content' => $content, - ); - - // Special handling of error messages - $messages = drupal_set_message(); - if (isset($messages['error'])) { - $title = count($messages['error']) > 1 ? st('The following errors must be resolved before you can continue the installation process') : st('The following error must be resolved before you can continue the installation process'); - $variables['messages'] .= '

'. $title .':

'; - $variables['messages'] .= theme('status_messages', 'error'); - $variables['content'] .= '

'. st('Please check the error messages and try again.', array('!url' => request_uri())) .'

'; - } - - // Special handling of status messages - if (isset($messages['status'])) { - $warnings = count($messages['status']) > 1 ? st('The following installation warnings should be carefully reviewed, but in most cases may be safely ignored') : st('The following installation warning should be carefully reviewed, but in most cases may be safely ignored'); - $variables['messages'] .= '

'. $title .':

'; - $variables['messages'] .= theme('status_messages', 'status'); - } - - return theme_render_template('misc/maintenance.tpl.php', $variables); -} - -/** - * Return a themed list of maintenance tasks to perform. - * - * Note: this function is not themeable. - */ -function theme_task_list($items, $active = NULL) { - $done = isset($items[$active]) || $active == NULL; - $output = '
    '; - foreach ($items as $k => $item) { - if ($active == $k) { - $class = 'active'; - $done = false; - } - else { - $class = $done ? 'done' : ''; - } - $output .= '
  1. '. $item .'
  2. '; - } - $output .= '
'; - return $output; -} - /** * Return a themed set of status and/or error messages. The messages are grouped * by type. @@ -1733,11 +1611,21 @@ function template_preprocess(&$variables, $hook) { // Tell all templates where they are located. $variables['directory'] = path_to_theme(); - // Flag front page status. - $variables['is_front'] = drupal_is_front_page(); - // Tell all templates by which kind of user they're viewed. - $variables['logged_in'] = ($user->uid > 0); - $variables['is_admin'] = user_access('access administration pages'); + + // Set default variables that depend on the database. + $variables['is_admin'] = FALSE; + $variables['is_front'] = FALSE; + $variables['logged_in'] = FALSE; + if ($variables['db_is_active'] = db_is_active()) { + // Check for administrators. + if (user_access('access administration pages')) { + $variables['is_admin'] = TRUE; + } + // Flag front page status. + $variables['is_front'] = drupal_is_front_page(); + // Tell all templates by which kind of user they're viewed. + $variables['logged_in'] = ($user->uid > 0); + } } /** @@ -1750,6 +1638,9 @@ function template_preprocess(&$variables, $hook) { * Uses the arg() function to generate a series of page template suggestions * based on the current path. * + * Any changes to variables in this preprocessor should also be changed inside + * template_preprocess_maintenance_page() to keep all them consistent. + * * The $variables array contains the following arguments: * - $content * - $show_blocks @@ -1757,7 +1648,7 @@ function template_preprocess(&$variables, $hook) { * @see page.tpl.php */ function template_preprocess_page(&$variables) { - /* Add favicon */ + // Add favicon if (theme_get_setting('toggle_favicon')) { drupal_set_html_head(''); } diff --git a/includes/theme.maintenance.inc b/includes/theme.maintenance.inc new file mode 100644 index 000000000..cfc34e09b --- /dev/null +++ b/includes/theme.maintenance.inc @@ -0,0 +1,258 @@ +base_theme)) { + $base_theme[] = $new_base_theme = $themes[$themes[$ancestor]->base_theme]; + $ancestor = $themes[$ancestor]->base_theme; + } + _init_theme($themes[$theme], array_reverse($base_theme), '_theme_load_offline_registry'); + + // These are usually added from system_init() -except maintenance.css. + // When the database is inactive it's not called so we add it here. + drupal_add_css(drupal_get_path('module', 'system') .'/defaults.css', 'module'); + drupal_add_css(drupal_get_path('module', 'system') .'/system.css', 'module'); + drupal_add_css(drupal_get_path('module', 'system') .'/system-menus.css', 'module'); + drupal_add_css(drupal_get_path('module', 'system') .'/maintenance.css', 'module'); +} + +/** + * This builds the registry when the site needs to bypass any database calls. + */ +function _theme_load_offline_registry($theme, $base_theme = NULL, $theme_engine = NULL) { + $registry = _theme_build_registry($theme, $base_theme, $theme_engine); + _theme_set_registry($registry); +} + +/** + * Return a themed list of maintenance tasks to perform. + */ +function theme_task_list($items, $active = NULL) { + $done = isset($items[$active]) || $active == NULL; + $output = '
    '; + foreach ($items as $k => $item) { + if ($active == $k) { + $class = 'active'; + $done = false; + } + else { + $class = $done ? 'done' : ''; + } + $output .= '
  1. '. $item .'
  2. '; + } + $output .= '
'; + return $output; +} + +/** + * Generate a themed installation page. + * + * Note: this function is not themeable. + * + * @param $content + * The page content to show. + */ +function theme_install_page($content) { + drupal_set_header('Content-Type: text/html; charset=utf-8'); + + // Assign content. + $variables['content'] = $content; + // Delay setting the message variable so it can be processed below. + $variables['show_messages'] = FALSE; + // The maintenance preprocess function is recycled here. + template_preprocess_maintenance_page($variables); + + // Special handling of error messages + $messages = drupal_set_message(); + if (isset($messages['error'])) { + $title = count($messages['error']) > 1 ? st('The following errors must be resolved before you can continue the installation process') : st('The following error must be resolved before you can continue the installation process'); + $variables['messages'] .= '

'. $title .':

'; + $variables['messages'] .= theme('status_messages', 'error'); + $variables['content'] .= '

'. st('Please check the error messages and try again.', array('!url' => request_uri())) .'

'; + } + + // Special handling of status messages + if (isset($messages['status'])) { + $warnings = count($messages['status']) > 1 ? st('The following installation warnings should be carefully reviewed, but in most cases may be safely ignored') : st('The following installation warning should be carefully reviewed, but in most cases may be safely ignored'); + $variables['messages'] .= '

'. $title .':

'; + $variables['messages'] .= theme('status_messages', 'status'); + } + + return theme_render_template('themes/garland/maintenance-page.tpl.php', $variables); +} + +/** + * Generate a themed update page. + * + * Note: this function is not themeable. + * + * @param $content + * The page content to show. + * @param $show_messages + * Whether to output status and error messages. + * FALSE can be useful to postpone the messages to a subsequent page. + */ +function theme_update_page($content, $show_messages = TRUE) { + // Set required headers. + drupal_set_header('Content-Type: text/html; charset=utf-8'); + + // Assign content and show message flag. + $variables['content'] = $content; + $variables['show_messages'] = $show_messages; + // The maintenance preprocess function is recycled here. + template_preprocess_maintenance_page($variables); + + return theme_render_template('themes/garland/maintenance-page.tpl.php', $variables); +} + +/** + * The variables generated here is a mirror of template_preprocess_page(). + * This preprocessor will run it's course when theme_maintenance_page() is + * invoked. It is also used in theme_install_page() and theme_update_page() to + * keep all the variables consistent. + * + * An alternate template file of "maintenance-page-offline.tpl.php" can be + * used when the database is offline to hide errors and completely replace the + * content. + * + * The $variables array contains the following arguments: + * - $content + * - $show_blocks + * + * @see maintenance-page.tpl.php + */ +function template_preprocess_maintenance_page(&$variables) { + // Add favicon + if (theme_get_setting('toggle_favicon')) { + drupal_set_html_head(''); + } + + global $theme; + // Retrieve the theme data to list all available regions. + $theme_data = _system_theme_data(); + $regions = $theme_data[$theme]->info['regions']; + + // Get all region content set with drupal_set_content(). + foreach (array_keys($regions) as $region) { + // Assign region to a region variable. + $region_content = drupal_get_content($region); + isset($variables[$region]) ? $variables[$region] .= $region_content : $variables[$region] = $region_content; + } + + // Setup layout variable. + $variables['layout'] = 'none'; + if (!empty($variables['left'])) { + $variables['layout'] = 'left'; + } + if (!empty($variables['right'])) { + $variables['layout'] = ($variables['layout'] == 'left') ? 'both' : 'right'; + } + + // Construct page title + if (drupal_get_title()) { + $head_title = array(strip_tags(drupal_get_title()), variable_get('site_name', 'Drupal')); + } + else { + $head_title = array(variable_get('site_name', 'Drupal')); + if (variable_get('site_slogan', '')) { + $head_title[] = variable_get('site_slogan', ''); + } + } + $variables['head_title'] = implode(' | ', $head_title); + $variables['base_path'] = base_path(); + $variables['breadcrumb'] = ''; + $variables['feed_icons'] = ''; + $variables['footer_message'] = filter_xss_admin(variable_get('site_footer', FALSE)); + $variables['head'] = drupal_get_html_head(); + $variables['help'] = ''; + $variables['language'] = $GLOBALS['language']; + $variables['logo'] = theme_get_setting('logo'); + $variables['messages'] = $variables['show_messages'] ? theme('status_messages') : ''; + $variables['mission'] = ''; + $variables['primary_links'] = array(); + $variables['secondary_links'] = array(); + $variables['search_box'] = ''; + $variables['site_name'] = (theme_get_setting('toggle_name') ? variable_get('site_name', 'Drupal') : ''); + $variables['site_slogan'] = (theme_get_setting('toggle_slogan') ? variable_get('site_slogan', '') : ''); + $variables['css'] = drupal_add_css(); + $variables['styles'] = drupal_get_css(); + $variables['scripts'] = drupal_get_js(); + $variables['tabs'] = ''; + $variables['title'] = drupal_get_title(); + $variables['closure'] = ''; + + // Compile a list of classes that are going to be applied to the body element. + $body_classes = array(); + $body_classes[] = 'in-maintenance'; + if (isset($variables['db_is_active']) && !$variables['db_is_active']) { + $body_classes[] = 'db-offline'; + } + if ($variables['layout'] == 'both') { + $body_classes[] = 'two-sidebars'; + } + elseif ($variables['layout'] == 'none') { + $body_classes[] = 'no-sidebars'; + } + else { + $body_classes[] = 'one-sidebar sidebar-'. $variables['layout']; + } + $variables['body_classes'] = implode(' ', $body_classes); + + // Dead databases will show error messages so supplying this template will + // allow themers to override the page and the content completely. + if (isset($variables['db_is_active']) && !$variables['db_is_active']) { + $variables['template_file'] = 'maintenance-page-offline'; + } +} -- cgit v1.2.3