diff options
-rw-r--r-- | includes/common.inc | 16 | ||||
-rw-r--r-- | includes/theme.inc | 39 | ||||
-rw-r--r-- | includes/theme.maintenance.inc | 3 | ||||
-rw-r--r-- | modules/simpletest/tests/theme.test | 35 | ||||
-rw-r--r-- | modules/simpletest/tests/theme_test.module | 59 | ||||
-rw-r--r-- | themes/tests/test_theme/template.php | 11 |
6 files changed, 129 insertions, 34 deletions
diff --git a/includes/common.inc b/includes/common.inc index 959675f8b..afb08eafd 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -4592,13 +4592,19 @@ function _drupal_bootstrap_full() { // Initialize $_GET['q'] prior to invoking hook_init(). drupal_path_initialize(); - // Set a custom theme for the current page, if there is one. We need to run - // this before invoking hook_init(), since any modules which initialize the - // theme system will prevent a custom theme from being correctly set later. - menu_set_custom_theme(); - // Let all modules take action before menu system handles the request + + // Let all modules take action before the menu system handles the request. // We do not want this while running update.php. if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') { + // Prior to invoking hook_init(), initialize the theme (potentially a custom + // one for this page), so that: + // - Modules with hook_init() implementations that call theme() or + // theme_get_registry() don't initialize the incorrect theme. + // - The theme can have hook_*_alter() implementations affect page building + // (e.g., hook_form_alter(), hook_node_view_alter(), hook_page_alter()), + // ahead of when rendering starts. + menu_set_custom_theme(); + drupal_theme_initialize(); module_invoke_all('init'); } } diff --git a/includes/theme.inc b/includes/theme.inc index eb7111a47..a696117cf 100644 --- a/includes/theme.inc +++ b/includes/theme.inc @@ -221,8 +221,8 @@ function _drupal_theme_initialize($theme, $base_theme = array(), $registry_callb } } - if (function_exists($registry_callback)) { - $registry_callback($theme, $base_theme, $theme_engine); + if (isset($registry_callback)) { + _theme_registry_callback($registry_callback, array($theme, $base_theme, $theme_engine)); } } @@ -233,26 +233,30 @@ function _drupal_theme_initialize($theme, $base_theme = array(), $registry_callb * The theme registry array if it has been stored in memory, NULL otherwise. */ function theme_get_registry() { - return _theme_set_registry(); + static $theme_registry = NULL; + + if (!isset($theme_registry)) { + list($callback, $arguments) = _theme_registry_callback(); + $theme_registry = call_user_func_array($callback, $arguments); + } + + return $theme_registry; } /** - * Store the theme registry in memory. - * - * @param $registry - * A registry array as returned by _theme_build_registry() + * Set the callback that will be used by theme_get_registry() to fetch the registry. * - * @return - * The theme registry array stored in memory + * @param $callback + * The name of the callback function. + * @param $arguments + * The arguments to pass to the function. */ -function _theme_set_registry($registry = NULL) { - static $theme_registry = NULL; - - if (isset($registry)) { - $theme_registry = $registry; +function _theme_registry_callback($callback = NULL, array $arguments = array()) { + static $stored; + if (isset($callback)) { + $stored = array($callback, $arguments); } - - return $theme_registry; + return $stored; } /** @@ -271,7 +275,6 @@ function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL) $cache = cache_get("theme_registry:$theme->name", 'cache'); if (isset($cache->data)) { $registry = $cache->data; - _theme_set_registry($registry); } else { // If not, build one and cache it. @@ -280,9 +283,9 @@ function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL) // complete set of theme hooks. if (module_load_all(NULL)) { _theme_save_registry($theme, $registry); - _theme_set_registry($registry); } } + return $registry; } /** diff --git a/includes/theme.maintenance.inc b/includes/theme.maintenance.inc index 927499a8f..419d300f1 100644 --- a/includes/theme.maintenance.inc +++ b/includes/theme.maintenance.inc @@ -88,8 +88,7 @@ function _drupal_maintenance_theme() { * 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 _theme_build_registry($theme, $base_theme, $theme_engine); } /** diff --git a/modules/simpletest/tests/theme.test b/modules/simpletest/tests/theme.test index d4dc89842..f6dea3309 100644 --- a/modules/simpletest/tests/theme.test +++ b/modules/simpletest/tests/theme.test @@ -66,6 +66,14 @@ class ThemeUnitTest extends DrupalWebTestCase { $_GET['q'] = $q; $this->assertTrue(in_array('page__front', $suggestions), t('Front page template was suggested.')); } + + /** + * Ensures theme hook_*_alter() implementations can run before anything is rendered. + */ + function testAlter() { + $this->drupalGet('theme-test/alter'); + $this->assertText('The altered data is test_theme_theme_test_alter_alter was invoked.', t('The theme was able to implement an alter hook during page building before anything was rendered.')); + } } /** @@ -181,3 +189,30 @@ class ThemeHookInitUnitTest extends DrupalWebTestCase { $this->assertRaw('bartik/css/style.css', t("The default theme's CSS appears on the page when the theme system is initialized in hook_init().")); } } + +/** + * Tests autocompletion not loading registry. + */ +class ThemeFastTestCase extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => 'Theme fast initialization', + 'description' => 'Test that autocompletion does not load the registry.', + 'group' => 'Theme' + ); + } + + function setUp() { + parent::setUp('theme_test'); + $this->account = $this->drupalCreateUser(array('access user profiles')); + } + + /** + * Tests access to user autocompletion and verify the correct results. + */ + function testUserAutocomplete() { + $this->drupalLogin($this->account); + $this->drupalGet('user/autocomplete/' . $this->account->name); + $this->assertText('registry not initialized', t('The registry was not initialized')); + } +} diff --git a/modules/simpletest/tests/theme_test.module b/modules/simpletest/tests/theme_test.module index ad22367b8..ff525ec34 100644 --- a/modules/simpletest/tests/theme_test.module +++ b/modules/simpletest/tests/theme_test.module @@ -12,6 +12,13 @@ function theme_test_menu() { 'theme callback' => '_theme_custom_theme', 'type' => MENU_CALLBACK, ); + $items['theme-test/alter'] = array( + 'title' => 'Suggestion', + 'page callback' => '_theme_test_alter', + 'access arguments' => array('access content'), + 'theme callback' => '_theme_custom_theme', + 'type' => MENU_CALLBACK, + ); $items['theme-test/hook-init'] = array( 'page callback' => 'theme_test_hook_init_page_callback', 'access callback' => TRUE, @@ -24,15 +31,36 @@ function theme_test_menu() { * Implements hook_init(). */ function theme_test_init() { - // First, force the theme registry to be rebuilt on this page request. This - // allows us to test a full initialization of the theme system in the code - // below. - drupal_theme_rebuild(); - // Next, initialize the theme system by storing themed text in a global - // variable. We will use this later in theme_test_hook_init_page_callback() - // to test that even when the theme system is initialized this early, it is - // still capable of returning output and theming the page as a whole. - $GLOBALS['theme_test_output'] = theme('more_link', array('url' => 'user', 'title' => 'Themed output generated in hook_init()')); + if (arg(0) == 'theme-test' && arg(1) == 'hook-init') { + // First, force the theme registry to be rebuilt on this page request. This + // allows us to test a full initialization of the theme system in the code + // below. + drupal_theme_rebuild(); + // Next, initialize the theme system by storing themed text in a global + // variable. We will use this later in theme_test_hook_init_page_callback() + // to test that even when the theme system is initialized this early, it is + // still capable of returning output and theming the page as a whole. + $GLOBALS['theme_test_output'] = theme('more_link', array('url' => 'user', 'title' => 'Themed output generated in hook_init()')); + } +} + +/** + * Implements hook_exit(). + */ +function theme_test_exit() { + if (arg(0) == 'user') { + // Register a fake registry loading callback. If it gets called by + // theme_get_registry(), the registry has not been initialized yet. + _theme_registry_callback('_theme_test_load_registry', array()); + print theme_get_registry() ? 'registry initialized' : 'registry not initialized'; + } +} + +/** + * Fake registry loading callback. + */ +function _theme_test_load_registry() { + return array(); } /** @@ -50,6 +78,19 @@ function _theme_custom_theme() { } /** + * Page callback, calls drupal_alter(). + * + * This is for testing that the theme can have hook_*_alter() implementations + * that run during page callback execution, even before theme() is called for + * the first time. + */ +function _theme_test_alter() { + $data = 'foo'; + drupal_alter('theme_test_alter', $data); + return "The altered data is $data."; +} + +/** * Page callback, calls a theme hook suggestion. */ function _theme_test_suggestion() { diff --git a/themes/tests/test_theme/template.php b/themes/tests/test_theme/template.php index 944c23690..3d8b656c7 100644 --- a/themes/tests/test_theme/template.php +++ b/themes/tests/test_theme/template.php @@ -9,3 +9,14 @@ function test_theme_breadcrumb__suggestion($variables) { // when the suggestion has an implementation. return 'test_theme_breadcrumb__suggestion: ' . $variables['theme_test_preprocess_breadcrumb']; } + +/** + * Tests a theme implementing an alter hook. + * + * The confusing function name here is due to this being an implementation of + * the alter hook invoked when the 'theme_test' module calls + * drupal_alter('theme_test_alter'). + */ +function test_theme_theme_test_alter_alter(&$data) { + $data = 'test_theme_theme_test_alter_alter was invoked'; +} |