summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2010-08-22 12:46:21 +0000
committerDries Buytaert <dries@buytaert.net>2010-08-22 12:46:21 +0000
commitb0894ceaa74c01444856910fd87dfc992542eb85 (patch)
tree5dbbd695351e7344279e27b32454beede85b53e2
parentee691c593adfaf4c8046cf6ee2bc9796a28a1448 (diff)
downloadbrdo-b0894ceaa74c01444856910fd87dfc992542eb85.tar.gz
brdo-b0894ceaa74c01444856910fd87dfc992542eb85.tar.bz2
- Patch #812016 by effulgentsia, chx, redndahead, Damien Tournoud: themes cannot always participate in drupal_alter().
-rw-r--r--includes/common.inc16
-rw-r--r--includes/theme.inc39
-rw-r--r--includes/theme.maintenance.inc3
-rw-r--r--modules/simpletest/tests/theme.test35
-rw-r--r--modules/simpletest/tests/theme_test.module59
-rw-r--r--themes/tests/test_theme/template.php11
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';
+}