diff --git a/includes/theme.inc b/includes/theme.inc index c211248..acee080 100644 --- a/includes/theme.inc +++ b/includes/theme.inc @@ -279,28 +279,7 @@ function _theme_registry_callback($callback = NULL, array $arguments = array()) * The name of the theme engine. */ function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL) { - // Check the theme registry cache; if it exists, use it. - $cache = cache_get("theme_registry:$theme->name", 'cache'); - if (isset($cache->data)) { - $registry = $cache->data; - } - else { - // If not, build one and cache it. - $registry = _theme_build_registry($theme, $base_theme, $theme_engine); - // Only persist this registry if all modules are loaded. This assures a - // complete set of theme hooks. - if (module_load_all(NULL)) { - _theme_save_registry($theme, $registry); - } - } - return $registry; -} - -/** - * Write the theme_registry cache into the database. - */ -function _theme_save_registry($theme, $registry) { - cache_set("theme_registry:$theme->name", $registry); + return new ThemeRegistry($theme, $base_theme, $theme_engine); } /** @@ -563,6 +542,113 @@ function _theme_build_registry($theme, $base_theme, $theme_engine) { } /** + * Builds the run-time theme registry. + * + * This class extends the ArrayAccess class to allow the theme registry to be + * accessed as a complete registry, while internally only loading the parts of + * the registry that are actually in use for each request. On cache misses the + * complete theme registry for the theme will be loaded, and the run-time cache + * updated. + */ +Abstract class ThemeRegistry Implements ArrayAccess { + protected $registry = array(); + + function __construct($theme, $base_theme = NULL, $theme_engine = NULL) { + // Make the arguments available to the rest of the class. + $this->theme = $theme; + $this->base_theme = $base_theme; + $this->theme_engine = $theme_engine; + + // Load the run-time theme registry from cache if available. + if ($cached = cache_get("theme_registry:$theme->name", 'cache')) { + $this->registry = $cached->data; + } + } + + public function offsetExists($offset) { + // The values of the theme registry are always arrays, so ensure that the + // value is non-empty. + if (!empty($this->registry[$offset])) { + return TRUE; + } + // If the value is isset but empty, this is a cached miss for a theme key. + else { + if (isset($this->registry[$offset])) { + return FALSE; + } + else { + // If the key is not available, load it from the complete theme + // registry, then re-run this method. + $this->resolveRegistry($offset); + return $this->offsetExists($offset); + } + } + } + + public function offsetGet($offset) { + if (!empty($this->registry[$offset])) { + return $this->registry[$offset]; + } + else { + if (isset($this->registry[$offset])) { + return NULL; + } + else { + $this->resolveRegistry($offset); + return $this->offsetGet($offset); + } + } + } + + public function offsetSet($offset, $value) { + if (!isset($offset)) { + $this->registry[$offset] = $value; + } + else { + $this->registry[] = $value; + } + } + + public function offsetUnset($offset) { + unset($this->registry[$offset]); + } + + /** + * Resolve cache misses from the run-time registry. + * + * @param $offset + * The array key requested. + */ + public function resolveRegistry($offset) { + $this->cacheMiss = TRUE; + // Load the full theme registry. + if ($cached = cache_get('theme_registry:complete:' . $this->theme->name)) { + $completeRegistry = $cached->data; + } + else { + $completeRegistry = _theme_build_registry($this->theme, $this->base_theme, $this->theme_engine); + // Only persist this registry if all modules are loaded. This assures a + // complete set of theme hooks. + if (module_load_all(NULL)) { + cache_set('theme_registry:complete:' . $this->theme->name, $completeRegistry); + } + } + if (isset($completeRegistry[$offset])) { + $this->registry[$offset] = $completeRegistry[$offset]; + } + else { + $this->registry[$offset] = FALSE; + } + } + + public function __destruct() { + if (!empty($this->cacheMiss) && module_load_all(NULL)) { + cache_set('theme_registry:' . $this->theme->name, $this->registry); + } + } +} + +/** * Return a list of all currently available themes. * * Retrieved from the database, if available and the site is not in maintenance