diff --git a/core/includes/errors.inc b/core/includes/errors.inc index e015614..5fc4b7d 100644 --- a/core/includes/errors.inc +++ b/core/includes/errors.inc @@ -265,7 +265,6 @@ function _drupal_log_error($error, $fatal = FALSE) { // Generate a backtrace containing only scalar argument values. $message .= '
' . format_backtrace($backtrace) . '
'; } - echo "
"; var_dump($message); echo "
\n"; drupal_set_message($message, $class, TRUE); } diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 9b73531..e16c8d2 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -8,7 +8,6 @@ * customized by user themes. */ -use Drupal\Component\Utility\NestedArray; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Template\Attribute; use Drupal\Core\Theme\Registry; @@ -138,10 +137,8 @@ function drupal_theme_initialize() { * 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 _drupal_theme_initialize($theme, $base_theme = array(), $registry_callback = '_theme_load_registry') { +function _drupal_theme_initialize($theme, $base_theme = array()) { global $theme_info, $base_theme_info, $theme_engine, $theme_path; $theme_info = $theme; $base_theme_info = $base_theme; @@ -268,15 +265,9 @@ function _drupal_theme_initialize($theme, $base_theme = array(), $registry_callb } } // Load twig as secondary always available engine. - // @todo Make twig the default engine and remove this. This is required - // because (by design) the theme system doesn't allow modules to register more - // than one type of extension. We need a temporary backwards compatibility - // layer to allow us to perform core-wide .tpl.php to .twig conversion. + // @todo Replace this hack with generic $theme->engine loading (including base + // themes). include_once DRUPAL_ROOT . '/core/themes/engines/twig/twig.engine'; - - if (isset($registry_callback)) { - _theme_registry_callback($registry_callback, array($theme, $base_theme, $theme_engine)); - } } /** @@ -312,74 +303,12 @@ function theme_get_registry($complete = TRUE) { } /** - * Sets the callback that will be used by theme_get_registry(). - * - * @param $callback - * The name of the callback function. - * @param $arguments - * The arguments to pass to the function. - */ -function _theme_registry_callback($callback = NULL, array $arguments = array()) { - static $stored; - if (isset($callback)) { - $stored = array($callback, $arguments); - } - return $stored; -} - -/** - * Gets the theme_registry cache; if it doesn't exist, builds it. - * - * @param $theme - * The loaded $theme object as returned by list_themes(). - * @param $base_theme - * An array of loaded $theme objects representing the ancestor themes in - * oldest first order. - * @param $theme_engine - * The name of the theme engine. - * @param $complete - * Whether to load the complete theme registry or an instance of the - * Drupal\Core\Utility\ThemeRegistry class. - * - * @return - * The theme registry array, or an instance of the - * Drupal\Core\Utility\ThemeRegistry class. - */ -function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL, $complete = TRUE) { - if ($complete) { - // Check the theme registry cache; if it exists, use it. - $cached = cache()->get("theme_registry:$theme->name"); - if (isset($cached->data)) { - $registry = $cached->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; - } - else { - return new ThemeRegistry('theme_registry:runtime:' . $theme->name, 'cache', array('theme_registry' => TRUE)); - } -} - -/** - * Writes the theme_registry cache into the database. - */ -function _theme_save_registry($theme, $registry) { - cache()->set("theme_registry:$theme->name", $registry, CacheBackendInterface::CACHE_PERMANENT, array('theme_registry' => TRUE)); -} - -/** * Forces the system to rebuild the theme registry. * * This function should be called when modules are added to the system, or when * a dynamic system needs to add more theme hooks. + * + * @todo Remove this. */ function drupal_theme_rebuild() { drupal_static_reset('theme_get_registry'); @@ -387,406 +316,6 @@ function drupal_theme_rebuild() { } /** - * Process a single implementation of hook_theme(). - * - * @param $cache - * The theme registry that will eventually be cached; It is an associative - * array keyed by theme hooks, whose values are associative arrays describing - * the hook: - * - 'type': The passed-in $type. - * - 'theme path': The passed-in $path. - * - 'function': The name of the function generating output for this theme - * hook. Either defined explicitly in hook_theme() or, if neither - * 'function' nor 'template' is defined, then the default theme function - * name is used. The default theme function name is the theme hook prefixed - * by either 'theme_' for modules or '$name_' for everything else. If - * 'function' is defined, 'template' is not used. - * - 'template': The filename of the template generating output for this - * theme hook. The template is in the directory defined by the 'path' key of - * hook_theme() or defaults to "$path/templates". - * - 'variables': The variables for this theme hook as defined in - * hook_theme(). If there is more than one implementation and 'variables' - * is not specified in a later one, then the previous definition is kept. - * - 'render element': The renderable element for this theme hook as defined - * in hook_theme(). If there is more than one implementation and - * 'render element' is not specified in a later one, then the previous - * definition is kept. - * - 'preprocess functions': See theme() for detailed documentation. - * - 'process functions': See theme() for detailed documentation. - * @param $name - * The name of the module, theme engine, base theme engine, theme or base - * theme implementing hook_theme(). - * @param $type - * One of 'module', 'theme_engine', 'base_theme_engine', 'theme', or - * 'base_theme'. Unlike regular hooks that can only be implemented by modules, - * each of these can implement hook_theme(). _theme_process_registry() is - * called in aforementioned order and new entries override older ones. For - * example, if a theme hook is both defined by a module and a theme, then the - * definition in the theme will be used. - * @param $theme - * The loaded $theme object as returned from list_themes(). - * @param $path - * The directory where $name is. For example, modules/system or - * themes/bartik. - * - * @see theme() - * @see _theme_process_registry() - * @see hook_theme() - * @see list_themes() - */ -function _theme_process_registry(&$cache, $name, $type, $theme, $path) { - $result = array(); - - // Processor functions work in two distinct phases with the process - // functions always being executed after the preprocess functions. - $variable_process_phases = array( - 'preprocess functions' => 'preprocess', - 'process functions' => 'process', - ); - - $hook_defaults = array( - 'variables' => TRUE, - 'render element' => TRUE, - 'pattern' => TRUE, - 'base hook' => TRUE, - ); -// echo "
CACHE: "; var_dump($cache['maintenance_page']); echo "
\n"; -// echo "
"; var_dump($type, $theme, $path); echo "
\n"; - - // Invoke the hook_theme() implementation, process what is returned, and - // merge it into $cache. - $function = $name . '_theme'; - if (function_exists($function)) { - $result = $function($cache, $type, $theme, $path); - - // Prepare prefixes for processor functions. - $prefixes = array(); - if ($type == 'module') { - // Default variable processor prefix. - $prefixes[] = 'template'; - // Add all modules so they can intervene with their own variable - // processors. This allows them to provide variable processors even if - // they are not the owner of the current hook. - $prefixes += module_list(); - } - elseif ($type == 'theme_engine' || $type == 'base_theme_engine') { - // Theme engines get an extra set that come before the normally - // named variable processors. - $prefixes[] = $name . '_engine'; - // The theme engine registers on behalf of the theme using the - // theme's name. - $prefixes[] = $theme; - } - else { - // This applies when the theme manually registers their own variable - // processors. - $prefixes[] = $name; - } - - foreach ($result as $hook => $info) { - // When a theme or engine overrides a module's theme function - // $result[$hook] will only contain key/value pairs for information being - // overridden. Pull the rest of the information from what was defined by - // an earlier hook. - - // Fill in the type and path of the module, theme, or engine that - // implements this theme function. - - // Preserve existing theme hook info. - if (isset($cache[$hook])) { -// echo "
"; var_dump($result[$hook]); echo "
\n"; - $result[$hook] = NestedArray::mergeDeep($cache[$hook], $info); -// $result[$hook] = array_merge($cache[$hook], $info); -// echo "
"; var_dump($result[$hook]); echo "
\n"; - } - else { - $result[$hook]['type'] = $type; - $result[$hook]['theme path'] = $path; - } - - // If function and file are omitted, default to standard naming - // conventions. - if (!isset($info['template']) && !isset($info['function'])) { - $result[$hook]['function'] = ($type == 'module' ? 'theme_' : $name . '_') . $hook; - } - - // Collect previously set files for inclusion. - if (isset($cache[$hook]['includes'])) { - $result[$hook]['includes'] = $cache[$hook]['includes']; - } - - // If the theme implementation defines a file, then also use the path - // that it defined. Otherwise use the default path. This allows - // system.module to declare theme functions on behalf of core .include - // files. These files will be included once by theme() calls. - if (isset($info['file'])) { - $include_file = isset($info['path']) ? $info['path'] : $path; - $include_file .= '/' . $info['file']; - include_once DRUPAL_ROOT . '/' . $include_file; - $result[$hook]['includes'][] = $include_file; - } - - // The following apply only to theming hooks implemented as templates. - if (isset($info['template'])) { - // Prepend the current theming path when none is set. - if (!isset($info['path'])) { - $result[$hook]['template'] = $path . '/templates/' . $info['template']; - } - if (TRUE || $type == 'module') { - // Add two render engines for modules. - // @todo Remove and make twig the default engine. - $render_engines = array( - '.twig' => 'twig', - '.tpl.php' => 'phptemplate' - ); - - // Find the best engine for this template. - foreach ($render_engines as $extension => $engine) { - // Render the output using the template file. - $template_file = $result[$hook]['template'] . $extension; - if (isset($info['path'])) { - $template_file = $info['path'] . '/' . $template_file; - } - if (file_exists($template_file)) { - $result[$hook]['template_file'] = $template_file; - $result[$hook]['engine'] = $engine; - break; - } - } - } - } - - // Allow variable processors for all theming hooks, whether the hook is - // implemented as a template or as a function. - foreach ($variable_process_phases as $phase_key => $phase) { - if (!isset($info[$phase_key])) { - // Check for existing variable processors set through hook_theme(). - $info += array($phase_key => array()); - - // If the default implementation is a function, but a template - // overrides that default implementation, introduce the default - // template processors. It is assumed that when it is implemented as - // a theme function, it must run as quickly as possible so only the - // default varible processors are introduced. The ones provided by - // modules not directly related to this theming hook will be ignored. - $current_prefixes = $prefixes; - if (isset($cache[$hook]['function']) && $cache[$hook]['type'] === 'module' && isset($info['template'])) { - $current_prefixes = array_merge(array('template'), $current_prefixes); - } - - foreach ($current_prefixes as $prefix) { - // Only use non-hook-specific variable processors for theming hooks - // implemented as templates. See theme(). - if (isset($info['template']) && function_exists($prefix . '_' . $phase)) { - $info[$phase_key][] = $prefix . '_' . $phase; - } - if (function_exists($prefix . '_' . $phase . '_' . $hook)) { - $info[$phase_key][] = $prefix . '_' . $phase . '_' . $hook; - } - } - } - // Check for the override flag and prevent the cached variable - // processors from being used. This allows themes or theme engines to - // remove variable processors set earlier in the registry build. - if (!empty($info['override ' . $phase_key])) { - // Flag not needed inside the registry. - unset($result[$hook]['override ' . $phase_key]); - } - elseif (isset($cache[$hook][$phase_key])) { - $info[$phase_key] = array_merge($cache[$hook][$phase_key], $info[$phase_key]); - } - $result[$hook][$phase_key] = $info[$phase_key]; - } - } - - // Merge the newly created theme hooks into the existing cache. - if (isset($result['maintenance_page'])) { -// echo "
RESULT: "; var_dump($result['maintenance_page']); echo "
\n"; - } - $cache = $result + $cache; - } -// echo "
NEW CACHE: "; var_dump($cache['maintenance_page']); echo "
\n"; - - // 11/01/2013 sun: Note: The below code got removed previously. - - // Let themes have variable processors even if they didn't register a - // template. - if ($type == 'theme' || $type == 'base_theme') { - foreach ($cache as $hook => $info) { - // Check only if not registered by the theme or engine. - if (empty($result[$hook])) { - foreach ($variable_process_phases as $phase_key => $phase) { - if (!isset($info[$phase_key])) { - $cache[$hook][$phase_key] = array(); - } - // Only use non-hook-specific variable processors for theming hooks - // implemented as templates. See theme(). - if (isset($info['template']) && function_exists($name . '_' . $phase)) { - $cache[$hook][$phase_key][] = $name . '_' . $phase; - } - if (function_exists($name . '_' . $phase . '_' . $hook)) { - $cache[$hook][$phase_key][] = $name . '_' . $phase . '_' . $hook; - $cache[$hook]['theme path'] = $path; - } - // Ensure uniqueness. - $cache[$hook][$phase_key] = array_unique($cache[$hook][$phase_key]); - } - } - } - } -// echo "
NEW CACHE: "; var_dump($cache['maintenance_page']); echo "
\n"; -} - -/** - * Completes the theme registry, adding missing functions and hooks. - */ -function _theme_post_process_registry(&$cache, $theme, $base_theme, $theme_engine) { - // Get all user defined functions. - list(, $user_func) = array_values(get_defined_functions()); - $user_func = array_combine($user_func, $user_func); - - // Gather prefixes. This will be used to limit the found functions to the - // expected naming conventions. - $prefixes = module_list(); - if ($theme_engine) { - $prefixes[] = $theme_engine . '_engine'; - } - foreach ($base_theme as $base) { - $prefixes[] = $base->name; - } - $prefixes[] = $theme->name; - - // Collect all known hooks. Discovered functions must be based on a known - // hook. - $hooks = implode('|', array_keys($cache)); - - // Collect all variable processor functions in the correct order. - $processors = array(); - foreach ($prefixes as $prefix) { - $processors += preg_grep("/^{$prefix}_(pre)?process_($hooks)(__)?/", $user_func); - } - - // Add missing variable processors. This is needed for hooks that do not - // explicitly register the hook. For example, when a theme contains a variable - // process function but it does not implement a template, it will go missing. - // This will add the expected function. It also allows modules or themes to - // have a variable process function based on a pattern even if the hook does - // not exist. - foreach ($processors as $processor) { - $hook = substr($processor, strpos($processor, 'process_') + strlen('process_')); - $phase = strpos($processor, 'preprocess') ? 'preprocess functions' : 'process functions'; - - if (isset($cache[$hook][$phase]) && !in_array($processor, $cache[$hook][$phase])) { - // Add missing processor to existing hook. - $cache[$hook][$phase][] = $processor; - } - elseif (!isset($cache[$hook]) && strpos($hook, '__')) { - // Process non-existing hook and register it. - // Search for the base hook. - $base_hook = $hook; - while (!isset($cache[$base_hook]) && $pos = strrpos($base_hook, '__')) { - $base_hook = substr($base_hook, 0, $pos); - // If the current hook is based on a pattern, get the base hook. - if (isset($cache[$base_hook]['base hook'])) { - $base_hook = $cache[$base_hook]['base hook']; - } - } - if (isset($cache[$base_hook])) { - // Pull from the base hook and register the new - $cache[$hook] = $cache[$base_hook]; - if (isset($cache[$hook][$phase])) { - $cache[$hook][$phase][] = $processor; - } - } - } - } - - // Inherit all base hook variable processors into pattern hooks. This ensures - // that derivative hooks have a complete set of variable process functions. - foreach ($cache as $hook => $info) { - foreach (array('preprocess functions', 'process functions') as $phase) { - // The 'base hook' is only applied to derivative hooks already registered - // from a pattern. This is typically set from drupal_find_theme_functions() - // and drupal_find_theme_templates(). - if (isset($info['base hook']) && isset($cache[$info['base hook']][$phase])) { - $diff = array_diff($cache[$info['base hook']][$phase], $info[$phase]); - $cache[$hook][$phase] = array_merge($diff, $info[$phase]); - } - - // Optimize the registry. - if (isset($cache[$hook][$phase]) && empty($cache[$hook][$phase])) { - unset($cache[$hook][$phase]); - } - } - } -} - -/** - * Builds the theme registry cache. - * - * @param $theme - * The loaded $theme object as returned by list_themes(). - * @param $base_theme - * An array of loaded $theme objects representing the ancestor themes in - * oldest first order. - * @param $theme_engine - * The name of the theme engine. - */ -function _theme_build_registry($theme, $base_theme, $theme_engine) { - $cache = array(); - // First, process the theme hooks advertised by modules. This will - // serve as the basic registry. Since the list of enabled modules is the same - // regardless of the theme used, this is cached in its own entry to save - // building it for every theme. - if ($cached = cache()->get('theme_registry:build:modules')) { - $cache = $cached->data; - } - else { - foreach (module_implements('theme') as $module) { - _theme_process_registry($cache, $module, 'module', $module, drupal_get_path('module', $module)); - } - // Only cache this registry if all modules are loaded. - if (module_load_all(NULL)) { - cache()->set("theme_registry:build:modules", $cache, CacheBackendInterface::CACHE_PERMANENT, array('theme_registry' => TRUE)); - } - } - - // Process each base theme. - foreach ($base_theme as $base) { - // If the base theme uses a theme engine, process its hooks. - $base_path = dirname($base->filename); - if ($theme_engine) { - _theme_process_registry($cache, $theme_engine, 'base_theme_engine', $base->name, $base_path); - } - _theme_process_registry($cache, $base->name, 'base_theme', $base->name, $base_path); - } - - // And then the same thing, but for the theme. - if ($theme_engine) { - _theme_process_registry($cache, $theme_engine, 'theme_engine', $theme->name, dirname($theme->filename)); - } - - // Finally, hooks provided by the theme itself. - _theme_process_registry($cache, $theme->name, 'theme', $theme->name, dirname($theme->filename)); - - // Finalize the build. -# _theme_post_process_registry($cache, $theme, $base_theme, $theme_engine); - - // Let modules alter the registry. - drupal_alter('theme_registry', $cache); - - // Optimize the registry to not have empty arrays for functions. - foreach ($cache as $hook => $info) { - foreach (array('preprocess functions', 'process functions') as $phase) { - if (empty($info[$phase])) { - unset($cache[$hook][$phase]); - } - } - } - return $cache; -} - -/** * Returns a list of all currently available themes. * * Retrieved from the database, if available and the site is not in maintenance @@ -1063,7 +592,7 @@ function drupal_find_base_themes($themes, $key, $used_keys = array()) { function theme($hook, $variables = array()) { // If called before all modules are loaded, we do not necessarily have a full // theme registry to work with, and therefore cannot process the theme - // request properly. See also _theme_load_registry(). + // request properly. if (!module_load_all(NULL) && !defined('MAINTENANCE_MODE')) { throw new Exception(t('theme() may not be called until all modules are loaded.')); } @@ -1147,10 +676,6 @@ function theme($hook, $variables = array()) { $variables += array( 'theme_hook_original' => $original_hook, ); - echo "
"; var_dump($hook); echo "
\n"; - if ($hook == 'html') { - echo "
"; var_dump($info); echo "
\n"; - } // Invoke the variable processors, if any. The processors may specify // alternate suggestions for which hook's template/function to use. If the @@ -1167,22 +692,20 @@ function theme($hook, $variables = array()) { include_once DRUPAL_ROOT . '/' . $include_file; } } - if (isset($base_hook_info['preprocess functions']) || isset($base_hook_info['process functions'])) { + if (isset($base_hook_info['preprocess']) || isset($base_hook_info['process'])) { $variables['theme_hook_suggestion'] = $hook; $hook = $base_hook; $info = $base_hook_info; } } - if (isset($info['preprocess functions']) || isset($info['process functions'])) { + if (isset($info['preprocess']) || isset($info['process'])) { $variables['theme_hook_suggestions'] = array(); - foreach (array('preprocess functions', 'process functions') as $phase) { + foreach (array('preprocess', 'process') as $phase) { if (!empty($info[$phase])) { foreach ($info[$phase] as $processor_function) { - if (function_exists($processor_function)) { - // We don't want a poorly behaved process function changing $hook. - $hook_clone = $hook; - $processor_function($variables, $hook_clone); - } + // We don't want a poorly behaved process function changing $hook. + $hook_clone = $hook; + $processor_function($variables, $hook_clone); } } } @@ -1216,13 +739,7 @@ function theme($hook, $variables = array()) { // Generate the output using either a function or a template. $output = ''; if (!isset($info['template']) && isset($info['function'])) { - if (!function_exists($info['function'])) { - echo "
"; var_dump($GLOBALS['theme']); echo "
\n"; - echo "
"; var_dump($info); echo "
\n"; - } - if (function_exists($info['function'])) { - $output = $info['function']($variables); - } + $output = $info['function']($variables); } elseif (isset($info['template'])) { // Default render function and extension. @@ -1249,15 +766,12 @@ function theme($hook, $variables = array()) { } // Render the output using the template file. - $template_file = $info['template'] . $extension; - if (isset($info['path'])) { - $template_file = $info['path'] . '/' . $template_file; - } - - // Modules can override this. if (isset($info['template_file'])) { $template_file = $info['template_file']; } + else { + $template_file = $info['path'] . '/' . $info['template'] . $extension; + } $output = $render_function($template_file, $variables); } @@ -2997,12 +2511,6 @@ function template_process_page(&$variables) { function template_process_html(&$variables) { drupal_add_library('system', 'html5shiv', TRUE); drupal_add_library('system', 'modernizr', TRUE); - // Eh? - if (!isset($variables['page']['page_top']) || !is_array($variables['page']['page_top'])) { -// ddebug_backtrace(); - #echo "
"; var_dump(debug_backtrace()); echo "
\n"; - $variables['page']['page_top'] = array(); - } // Render page_top and page_bottom into top level variables. $variables['page_top'] = drupal_render($variables['page']['page_top']); $variables['page_bottom'] = drupal_render($variables['page']['page_bottom']); @@ -3380,6 +2888,7 @@ function drupal_common_theme() { // From form.inc. 'input' => array( 'render element' => 'element', + 'preprocess' => array('template_preprocess_input'), ), 'select' => array( 'render element' => 'element', diff --git a/core/includes/theme.maintenance.inc b/core/includes/theme.maintenance.inc index ba88661..7baa164 100644 --- a/core/includes/theme.maintenance.inc +++ b/core/includes/theme.maintenance.inc @@ -90,9 +90,11 @@ function _drupal_maintenance_theme() { /** * Builds the registry when the site needs to bypass any database calls. + * + * @todo Remove this. */ function _theme_load_offline_registry($theme, $base_theme = NULL, $theme_engine = NULL) { - return _theme_build_registry($theme, $base_theme, $theme_engine); + return theme_get_registry(); } /** diff --git a/core/lib/Drupal/Core/Theme/Registry.php b/core/lib/Drupal/Core/Theme/Registry.php index b8ea13f..ac2232f 100644 --- a/core/lib/Drupal/Core/Theme/Registry.php +++ b/core/lib/Drupal/Core/Theme/Registry.php @@ -12,40 +12,99 @@ use Drupal\Core\Utility\ThemeRegistry; /** - * + * Defines the theme registry service. + * + * @todo Replace local $registry variables in methods with $this->registry. */ class Registry { + /** + * The theme object representing the active theme for this registry. + * + * @var object + */ protected $theme; + + /** + * An array of base theme objects. + * + * @var array + */ protected $base_themes; - protected $theme_engine; + /** + * The name of the theme engine of $theme. + * + * @var string + */ + protected $engine; + + /** + * The complete theme registry. + * + * @var array + * An associative array keyed by theme hook names, whose values are + * associative arrays containing the aggregated hook definition: + * - type: The type of the extension the original theme hook originates + * from; e.g., 'module' for theme hook 'node' of Node module. + * - name: The name of the extension the original theme hook originates + * from; e.g., 'node' for theme hook 'node' of Node module. + * - theme path: The path to the extension denoted by 'type' and 'name'. + * @todo Remove 'theme path', it's useless. + * - includes: (optional) An array of include files to load when the theme + * hook is executed by theme(). + * - file: (optional) A filename to add to 'includes', either prefixed with + * the value of 'path', or the path of the extension implementing + * hook_theme(). + * In case of a theme base hook, one of the following: + * - variables: An associative array whose keys are variable names and whose + * values are default values of the variables to use for this theme hook. + * - render element: A string denoting the name of the variable name, in + * which the render element for this theme hook is provided. + * In case of a theme template file: + * - path: The path to the template file to use. Defaults to the + * subdirectory 'templates' of the path of the extension implementing + * hook_theme(); e.g., 'core/modules/node/templates' for Node module. + * - template: The basename of the template file to use, without extension + * (as the extension is specific to the theme engine). The template file + * is in the directory defined by 'path'. + * - template_file: A full path and file name to a template file to use. + * Allows any extension to override the effective template file. + * - engine: The theme engine to use for the template file. + * In case of a theme function: + * - function: The function name to call to generate the output. + * For any registered theme hook, including theme hook suggestions: + * - preprocess: An array of theme variable preprocess callbacks to invoke + * before invoking final theme variable processors. + * - process: An array of theme variable process callbacks to invoke + * before invoking the actual theme function or template. + */ protected $registry; - protected $partialRegistry; + /** + * The incomplete, runtime theme registry. + * + * @var \Drupal\Core\Utility\ThemeRegistry + */ + protected $runtimeRegistry; /** - * + * Constructs a new theme registry instance. + * * @param object $theme - * An object with the following information: - * filename - * The .info file for this theme. The 'path' to - * the theme will be in this file's directory. (Required) - * owner - * The path to the .theme file or the .engine file to load for - * the theme. (Required) - * stylesheet - * The primary stylesheet for the theme. (Optional) - * engine - * The name of theme engine to use. (Optional) + * An object with (at least) the following information: + * - uri: The path to the theme. + * - owner: The name of the theme's base theme. + * - engine: The name of the theme engine to use. * @param array $base_themes - * An optional array of objects that represent the 'base theme' if the - * theme is meant to be derivative of another theme. It requires - * the same information as the $theme object. It should be in - * 'oldest first' order, meaning the top level of the chain will - * be first. + * (optional) An array of objects that represent the base themes of $theme, + * each having the same properties as $theme above, ordered by base theme + * hierarchy; i.e., the first element is the root of all themes. * @param string $theme_engine * The name of the theme engine. + * + * @todo Remove $theme_engine, duplicates ->engine. + * @todo Stack all themes into a single $themes in appropriate order. */ public function __construct($theme, array $base_themes = array(), $theme_engine) { // @todo Inject Cache. @@ -56,7 +115,7 @@ public function __construct($theme, array $base_themes = array(), $theme_engine) } /** - * Gets the theme registry. + * Returns the complete theme registry. * * @param bool $complete * Optional boolean to indicate whether to return the complete theme registry @@ -68,9 +127,11 @@ public function __construct($theme, array $base_themes = array(), $theme_engine) * ArrayObject which allows it to be accessed with array syntax and isset(), * and should be more lightweight than the full registry. Defaults to TRUE. * - * @return + * @return array|\Drupal\Core\Utility\ThemeRegistry * The complete theme registry array, or an instance of the * Drupal\Core\Utility\ThemeRegistry class. + * + * @todo Refactor calling code to remove $complete parameter. */ public function get($complete = TRUE) { if ($complete) { @@ -80,27 +141,109 @@ public function get($complete = TRUE) { return $this->registry; } else { - if (!isset($this->partialRegistry)) { - $this->partialRegistry = $this->load(FALSE); + return $this->getRuntime(); + } + } + + /** + * Returns the incomplete, runtime theme registry. + * + * @return \Drupal\Core\Utility\ThemeRegistry + * An shared instance of the ThemeRegistry class, provides an ArrayObject + * that allows it to be accessed with array syntax and isset(), and is more + * lightweight than the full registry. + */ + public function getRuntime() { + if (!isset($this->runtimeRegistry)) { + $this->runtimeRegistry = new ThemeRegistry('theme_registry:runtime:' . $this->theme->name, 'cache', array('theme_registry' => TRUE)); + } + return $this->runtimeRegistry; + } + + /** + * Loads the theme registry from cache or rebuilds it. + * + * @param $complete + * Whether to load the complete theme registry or an instance of the + * Drupal\Core\Utility\ThemeRegistry class. + * + * @return array + * The complete theme registry array. + * + * @todo Remove $complete argument. @see ::get() + */ + public function load($complete = TRUE) { + if (!$complete) { + return $this->getRuntime(); + } + // Check the theme registry cache; if it exists, use it. + $cached = cache()->get('theme_registry:' . $this->theme->name); + if (isset($cached->data)) { + $registry = $cached->data; + } + else { + // If not, build one and cache it. + $registry = $this->build(); + // Only persist this registry if all modules are loaded. This assures a + // complete set of theme hooks. + if (module_load_all(NULL)) { + $this->save($registry); } - return $this->partialRegistry; } + return $registry; } + /** + * Sets the theme registry cache. + * + * @param array $registry + * The complete theme registry. + */ + public function save($registry) { + cache()->set('theme_registry:' . $this->theme->name, $registry, CacheBackendInterface::CACHE_PERMANENT, array('theme_registry' => TRUE)); + } + + /** + * Builds the theme registry from scratch. + * + * Theme hook definitions are collected in the following order: + * - Modules + * - Base theme engines + * - Base themes + * - Theme engine + * - Theme + * + * All theme hook definitions are essentially just collated and merged in the + * above order. However, various extension-specific default values and + * customizations are required; e.g., to record the effective file path for + * theme template. Therefore, this method first collects all extensions per + * type, and then dispatches the processing for each extension to + * processExtension(). + * + * @see hook_theme() + * + * After completing the collection, modules are allowed to alter it. Lastly, + * any derived and incomplete theme hook definitions that are hook suggestions + * for base hooks (e.g., 'block__node' for the base hook 'block') need to be + * determined based on the full registry and classified as 'base hook'. + * + * @see theme() + * @see hook_theme_registry_alter() + */ public function build() { + // @todo Replace local $registry variables in methods with $this->registry. $registry = array(); - // First, process the theme hooks advertised by modules. This will - // serve as the basic registry. Since the list of enabled modules is the same - // regardless of the theme used, this is cached in its own entry to save - // building it for every theme. + + // hook_theme() implementations of modules are always the same. if ($cached = cache()->get('theme_registry:build:modules')) { $registry = $cached->data; } else { foreach (module_implements('theme') as $module) { - $this->process($registry, $module, 'module', $module, drupal_get_path('module', $module)); + $this->processExtension($registry, 'module', $module, $module, drupal_get_path('module', $module)); } // Only cache this registry if all modules are loaded. + // @todo Get rid of these checks. if (module_load_all(NULL)) { cache()->set("theme_registry:build:modules", $registry, CacheBackendInterface::CACHE_PERMANENT, array('theme_registry' => TRUE)); } @@ -109,29 +252,42 @@ public function build() { // Process each base theme. foreach ($this->base_themes as $base) { // If the base theme uses a theme engine, process its hooks. - $base_path = dirname($base->filename); - if ($this->theme_engine) { - $this->process($registry, $this->theme_engine, 'base_theme_engine', $base->name, $base_path); + $base_path = dirname($base->uri); + if ($this->engine) { + $this->processExtension($registry, 'base_theme_engine', $this->engine, $base->name, $base_path); } - $this->process($registry, $base->name, 'base_theme', $base->name, $base_path); + $this->processExtension($registry, 'base_theme', $base->name, $base->name, $base_path); } // And then the same thing, but for the theme. - if ($this->theme_engine) { - $this->process($registry, $this->theme_engine, 'theme_engine', $theme->name, dirname($theme->filename)); + if ($this->engine) { + $this->processExtension($registry, 'theme_engine', $this->engine, $this->theme->name, dirname($this->theme->uri)); } - // Finally, hooks provided by the theme itself. - $this->process($registry, $theme->name, 'theme', $theme->name, dirname($theme->filename)); + $this->processExtension($registry, 'theme', $this->theme->name, $this->theme->name, dirname($this->theme->uri)); // Let modules alter the registry. drupal_alter('theme_registry', $registry); - // Optimize the registry to not have empty arrays for functions. - foreach ($registry as $hook => $info) { - foreach (array('preprocess functions', 'process functions') as $phase) { - if (empty($info[$phase])) { - unset($registry[$hook][$phase]); + // Map base hook suggestions and clean up unnecessary hooks. + foreach ($registry as $hook => &$info) { + if (empty($info['exists'])) { + // Determine whether this is a hook suggestion for an existing hook. + $base_hook = $hook; + // Iteratively strip everything after the last '__' delimiter, until an + // implementation is found. + while ($pos = strrpos($base_hook, '__')) { + $base_hook = substr($base_hook, 0, $pos); + if (isset($registry[$base_hook])) { + break; + } + } + if ($pos !== FALSE && $base_hook !== $hook) { + $info['base hook'] = $base_hook; + unset($info['exists']); + } + else { + unset($registry[$hook]); } } } @@ -141,296 +297,159 @@ public function build() { /** * Process a single implementation of hook_theme(). * - * @param $cache - * The theme registry that will eventually be cached; It is an associative - * array keyed by theme hooks, whose values are associative arrays describing - * the hook: - * - 'type': The passed-in $type. - * - 'theme path': The passed-in $path. - * - 'function': The name of the function generating output for this theme - * hook. Either defined explicitly in hook_theme() or, if neither - * 'function' nor 'template' is defined, then the default theme function - * name is used. The default theme function name is the theme hook prefixed - * by either 'theme_' for modules or '$name_' for everything else. If - * 'function' is defined, 'template' is not used. - * - 'template': The filename of the template generating output for this - * theme hook. The template is in the directory defined by the 'path' key of - * hook_theme() or defaults to "$path/templates". - * - 'variables': The variables for this theme hook as defined in - * hook_theme(). If there is more than one implementation and 'variables' - * is not specified in a later one, then the previous definition is kept. - * - 'render element': The renderable element for this theme hook as defined - * in hook_theme(). If there is more than one implementation and - * 'render element' is not specified in a later one, then the previous - * definition is kept. - * - 'preprocess functions': See theme() for detailed documentation. - * - 'process functions': See theme() for detailed documentation. - * @param $name - * The name of the module, theme engine, base theme engine, theme or base - * theme implementing hook_theme(). - * @param $type - * One of 'module', 'theme_engine', 'base_theme_engine', 'theme', or - * 'base_theme'. Unlike regular hooks that can only be implemented by modules, - * each of these can implement hook_theme(). _theme_process_registry() is - * called in aforementioned order and new entries override older ones. For - * example, if a theme hook is both defined by a module and a theme, then the - * definition in the theme will be used. - * @param $theme - * The loaded $theme object as returned from list_themes(). - * @param $path - * The directory where $name is. For example, modules/system or - * themes/bartik. + * @param array $registry + * The theme registry that will eventually be cached. + * @param string $type + * One of 'module', 'base_theme_engine', 'theme_engine', 'base_theme', or + * 'theme'. + * @param string $name + * The name of the extension implementing hook_theme(). + * @param string $theme_name + * The name of the extension for which theme hooks are currently processed. + * This equals $name for all extension types, except when $type is a theme + * engine, in which case $theme_name and $theme_path are pointing to the + * respective [base] theme the theme engine is associated with. + * @param string $theme_path + * The directory of $theme_name; e.g., 'core/modules/node' or + * 'themes/bartik'. * * @see theme() - * @see _theme_process_registry() * @see hook_theme() - * @see list_themes() */ - public function process(&$cache, $name, $type, $theme, $path) { - $result = array(); - - // Processor functions work in two distinct phases with the process - // functions always being executed after the preprocess functions. - $variable_process_phases = array( - 'preprocess functions' => 'preprocess', - 'process functions' => 'process', - ); - - $hook_defaults = array( - 'variables' => TRUE, - 'render element' => TRUE, - 'pattern' => TRUE, - 'base hook' => TRUE, - ); -// echo "
CACHE: "; var_dump($cache['maintenance_page']); echo "
\n"; -// echo "
"; var_dump($type, $theme, $path); echo "
\n"; - - // Invoke the hook_theme() implementation, process what is returned, and - // merge it into $cache. + public function processExtension(&$registry, $type, $name, $theme_name, $theme_path) { $function = $name . '_theme'; - if (function_exists($function)) { - $result = $function($cache, $type, $theme, $path); - - // Prepare prefixes for processor functions. - $prefixes = array(); - if ($type == 'module') { - // Default variable processor prefix. - $prefixes[] = 'template'; - // Add all modules so they can intervene with their own variable - // processors. This allows them to provide variable processors even if - // they are not the owner of the current hook. - $prefixes += module_list(); - } - elseif ($type == 'theme_engine' || $type == 'base_theme_engine') { - // Theme engines get an extra set that come before the normally - // named variable processors. - $prefixes[] = $name . '_engine'; - // The theme engine registers on behalf of the theme using the - // theme's name. - $prefixes[] = $theme; - } - else { - // This applies when the theme manually registers their own variable - // processors. - $prefixes[] = $name; + foreach ($function($registry, $type, $theme_name, $theme_path) as $hook => $info) { + // Ensure this hook key exists; it will be set either way. + $registry += array($hook => array( + 'type' => $type, + 'name' => $name, + )); + + if (isset($info['file'])) { + $include_path = isset($info['path']) ? $info['path'] : $theme_path; + $info['includes'][] = $include_path . '/' . $info['file']; + unset($info['file']); } - foreach ($result as $hook => $info) { - // When a theme or engine overrides a module's theme function - // $result[$hook] will only contain key/value pairs for information being - // overridden. Pull the rest of the information from what was defined by - // an earlier hook. - - // Fill in the type and path of the module, theme, or engine that - // implements this theme function. - - // Preserve existing theme hook info. - if (isset($cache[$hook])) { -// echo "
"; var_dump($result[$hook]); echo "
\n"; - $result[$hook] = NestedArray::mergeDeep($cache[$hook], $info); -// $result[$hook] = array_merge($cache[$hook], $info); -// echo "
"; var_dump($result[$hook]); echo "
\n"; - } - else { - $result[$hook]['type'] = $type; - $result[$hook]['theme path'] = $path; - } - - // If function and file are omitted, default to standard naming - // conventions. - if (!isset($info['template']) && !isset($info['function'])) { - $result[$hook]['function'] = ($type == 'module' ? 'theme_' : $name . '_') . $hook; - } + // An actual theme hook must define either 'variables' or a 'render element'. + if (isset($info['variables']) || isset($info['render element'])) { + $info['exists'] = TRUE; - // Collect previously set files for inclusion. - if (isset($cache[$hook]['includes'])) { - $result[$hook]['includes'] = $cache[$hook]['includes']; - } - - // If the theme implementation defines a file, then also use the path - // that it defined. Otherwise use the default path. This allows - // system.module to declare theme functions on behalf of core .include - // files. These files will be included once by theme() calls. - if (isset($info['file'])) { - $include_file = isset($info['path']) ? $info['path'] : $path; - $include_file .= '/' . $info['file']; - include_once DRUPAL_ROOT . '/' . $include_file; - $result[$hook]['includes'][] = $include_file; - } + // The effective path_to_theme() during theme(). + // @todo This variable is so horribly broken... remove it. + $info['theme path'] = $theme_path; - // The following apply only to theming hooks implemented as templates. if (isset($info['template'])) { - // Prepend the current theming path when none is set. + // A template implementation always takes precedence over functions. + // A potentially existing function pointer is obsolete. + unset($registry[$hook]['function']); + // Default the template path to the 'templates' directory of the + // extension, unless overridden. if (!isset($info['path'])) { - $result[$hook]['template'] = $path . '/templates/' . $info['template']; + $info['path'] = $theme_path . '/templates'; } - if (TRUE || $type == 'module') { - // Add two render engines for modules. - // @todo Remove and make twig the default engine. + // Find the preferred theme engine for this module template. + // @todo Remove and make Twig the default engine. + if ($type == 'module') { $render_engines = array( '.twig' => 'twig', - '.tpl.php' => 'phptemplate' + '.tpl.php' => 'phptemplate', ); - - // Find the best engine for this template. foreach ($render_engines as $extension => $engine) { // Render the output using the template file. - $template_file = $result[$hook]['template'] . $extension; - if (isset($info['path'])) { - $template_file = $info['path'] . '/' . $template_file; - } + $template_file = $info['path'] . '/' . $info['template'] . $extension; if (file_exists($template_file)) { - $result[$hook]['template_file'] = $template_file; - $result[$hook]['engine'] = $engine; + $info['template_file'] = $template_file; + $info['engine'] = $engine; break; } } } } - - // Allow variable processors for all theming hooks, whether the hook is - // implemented as a template or as a function. - foreach ($variable_process_phases as $phase_key => $phase) { - if (!isset($info[$phase_key])) { - // Check for existing variable processors set through hook_theme(). - $info += array($phase_key => array()); - - // If the default implementation is a function, but a template - // overrides that default implementation, introduce the default - // template processors. It is assumed that when it is implemented as - // a theme function, it must run as quickly as possible so only the - // default varible processors are introduced. The ones provided by - // modules not directly related to this theming hook will be ignored. - $current_prefixes = $prefixes; - if (isset($cache[$hook]['function']) && $cache[$hook]['type'] === 'module' && isset($info['template'])) { - $current_prefixes = array_merge(array('template'), $current_prefixes); - } - - foreach ($current_prefixes as $prefix) { - // Only use non-hook-specific variable processors for theming hooks - // implemented as templates. See theme(). - if (isset($info['template']) && function_exists($prefix . '_' . $phase)) { - $info[$phase_key][] = $prefix . '_' . $phase; - } - if (function_exists($prefix . '_' . $phase . '_' . $hook)) { - $info[$phase_key][] = $prefix . '_' . $phase . '_' . $hook; - } - } + // Otherwise, the implementation must be a function. However, functions + // do not need to be specified manually; the array key of the hook is + // expected to be taken over as function, unless overridden. + elseif (!isset($info['function'])) { + if ($type == 'module') { + $info['function'] = 'theme_' . $hook; } - // Check for the override flag and prevent the cached variable - // processors from being used. This allows themes or theme engines to - // remove variable processors set earlier in the registry build. - if (!empty($info['override ' . $phase_key])) { - // Flag not needed inside the registry. - unset($result[$hook]['override ' . $phase_key]); + else { + $info['function'] = $name . '_' . $hook; } - elseif (isset($cache[$hook][$phase_key])) { - $info[$phase_key] = array_merge($cache[$hook][$phase_key], $info[$phase_key]); - } - $result[$hook][$phase_key] = $info[$phase_key]; } } - - // Merge the newly created theme hooks into the existing cache. - if (isset($result['maintenance_page'])) { -// echo "
RESULT: "; var_dump($result['maintenance_page']); echo "
\n"; + // If no 'variables' or 'render element' was defined, then this hook + // definition extends an existing, or defines data for a hook suggestion. + // Data for hook suggestions requires a full registry in order to check + // for base hooks; therefore it happens after per-extension processing as + // last step in Registry::build(). + else { + // Revert the above theme engine hack for Twig, if the actual theme + // engine returns a template. + // @todo What an insane hack is this? Simply support multiple theme engines. + if ($type == 'theme_engine' && isset($info['template'])) { + unset($registry[$hook]['template_file']); + } } - $cache = $result + $cache; - } -// echo "
NEW CACHE: "; var_dump($cache['maintenance_page']); echo "
\n"; - // 11/01/2013 sun: Note: The below code got removed previously. + // If a template should be used, inject the default template_preprocess(). + // Also applies if the default implementation is a function, but a theme + // overrides it to a template. + if (isset($info['template']) && !isset($registry[$hook]['preprocess'])) { + $registry[$hook] += array('preprocess' => array()); - // Let themes have variable processors even if they didn't register a - // template. - if ($type == 'theme' || $type == 'base_theme') { - foreach ($cache as $hook => $info) { - // Check only if not registered by the theme or engine. - if (empty($result[$hook])) { - foreach ($variable_process_phases as $phase_key => $phase) { - if (!isset($info[$phase_key])) { - $cache[$hook][$phase_key] = array(); - } - // Only use non-hook-specific variable processors for theming hooks - // implemented as templates. See theme(). - if (isset($info['template']) && function_exists($name . '_' . $phase)) { - $cache[$hook][$phase_key][] = $name . '_' . $phase; - } - if (function_exists($name . '_' . $phase . '_' . $hook)) { - $cache[$hook][$phase_key][] = $name . '_' . $phase . '_' . $hook; - $cache[$hook]['theme path'] = $path; - } - // Ensure uniqueness. - $cache[$hook][$phase_key] = array_unique($cache[$hook][$phase_key]); - } + // Prepend global hook_preprocess() of modules. + $registry[$hook]['preprocess'] = array_merge($this->getHookImplementations('preprocess'), $registry[$hook]['preprocess']); + + // Prepend the base template_preprocess(). + array_unshift($registry[$hook]['preprocess'], 'template_preprocess'); + + // Once more for hook_process(), but only add the key if any enabled + // modules implement it, since there is no base template_process(). + if ($implementations = $this->getHookImplementations('process')) { + $registry[$hook] += array('process' => array()); + $registry[$hook]['process'] = array_merge($implementations, $registry[$hook]['process']); } } + + // Merge this extension's theme hook definition into the existing. + $registry[$hook] = NestedArray::mergeDeep($registry[$hook], $info); + + // Allow themes and theme engines to remove all (pre)process functions. + // @see hook_theme() + if (!empty($info['no preprocess'])) { + unset($registry[$hook]['preprocess']); + unset($registry[$hook]['no preprocess']); + } } -// echo "
NEW CACHE: "; var_dump($cache['maintenance_page']); echo "
\n"; } /** - * Loads the theme registry from cache. + * Retrieves module hook implementations for a given theme hook name. * - * @param $complete - * Whether to load the complete theme registry or an instance of the - * Drupal\Core\Utility\ThemeRegistry class. + * @param string $hook + * The hook name to discover. * - * @return - * The theme registry array, or an instance of the - * Drupal\Core\Utility\ThemeRegistry class. + * @return array + * An array of module hook implementations; i.e., the actual function names. */ - public function load($complete = TRUE) { - if ($complete) { - // Check the theme registry cache; if it exists, use it. - $cached = cache()->get('theme_registry:' . $this->theme->name); - if (isset($cached->data)) { - $registry = $cached->data; - } - else { - // If not, build one and cache it. - $registry = $this->build(); - // Only persist this registry if all modules are loaded. This assures a - // complete set of theme hooks. - if (module_load_all(NULL)) { - $this->save($registry); - } - } - return $registry; - } - else { - return new ThemeRegistry('theme_registry:runtime:' . $this->theme->name, 'cache', array('theme_registry' => TRUE)); - } + protected function getHookImplementations($hook) { + $implementations = module_implements($hook); + $add_suffix = function ($extension) use ($hook) { + return $extension . '_' . $hook; + }; + return array_map($add_suffix, $implementations); } /** - * Sets the theme registry cache. + * Invalidates theme registry caches and rebuilds the theme registry. * - * @param array $registry - * The complete theme registry. + * @return array + * The complete, rebuilt theme registry. */ - public function save($registry) { - cache()->set('theme_registry:' . $this->theme->name, $registry, CacheBackendInterface::CACHE_PERMANENT, array('theme_registry' => TRUE)); + public function rebuild() { + $this->reset(); + return $this->get(); } /** @@ -440,19 +459,12 @@ public function save($registry) { * a dynamic system needs to add more theme hooks. */ public function reset() { + unset($this->runtimeRegistry); unset($this->registry); - unset($this->partialRegistry); cache()->invalidateTags(array('theme_registry' => TRUE)); } /** - * Alias for reset(). - */ - public function rebuild() { - $this->reset(); - } - - /** * Allows themes and/or theme engines to discover overridden theme functions. * * @param $cache @@ -461,7 +473,9 @@ public function rebuild() { * An array of prefixes to test, in reverse order of importance. * * @return $implementations - * The functions found, suitable for returning from hook_theme; + * The functions found, suitable for returning from hook_theme(). + * + * @todo Currently unused. Convert this. */ public function findFunctions($cache, $prefixes) { $implementations = array(); @@ -517,6 +531,8 @@ public function findFunctions($cache, $prefixes) { * The extension that these templates will have. * @param $path * The path to search. + * + * @todo Currently unused. Convert this. */ public function findTemplates($cache, $extension, $path) { $implementations = array(); diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/FastTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/FastTest.php index 843106e..21742e4 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Theme/FastTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Theme/FastTest.php @@ -38,6 +38,7 @@ function setUp() { * Tests access to user autocompletion and verify the correct results. */ function testUserAutocomplete() { + // @todo Replace with injected mock registry in DUTB test. $this->drupalLogin($this->account); $this->drupalGet('user/autocomplete', array('query' => array('q' => $this->account->name))); $this->assertRaw($this->account->name); diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php index fd7542a..1ad6fa1 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php @@ -208,14 +208,8 @@ function testClassLoading() { * Tests drupal_find_theme_templates(). */ public function testFindThemeTemplates() { - $cache = array(); - - // Prime the theme cache. - foreach (module_implements('theme') as $module) { - _theme_process_registry($cache, $module, 'module', $module, drupal_get_path('module', $module)); - } - - $templates = drupal_find_theme_templates($cache, '.tpl.php', drupal_get_path('theme', 'test_theme')); + $registry = theme_get_registry(); + $templates = drupal_find_theme_templates($registry, '.tpl.php', drupal_get_path('theme', 'test_theme')); $this->assertEqual($templates['node__1']['template'], 'node--1', 'Template node--1.tpl.php was found in test_theme.'); } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTestTwig.php b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTestTwig.php index 6a9d988..5abb4bc 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTestTwig.php +++ b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTestTwig.php @@ -47,13 +47,7 @@ function testTemplateOverride() { * Tests drupal_find_theme_templates */ function testFindThemeTemplates() { - - $cache = array(); - - // Prime the theme cache - foreach (module_implements('theme') as $module) { - _theme_process_registry($cache, $module, 'module', $module, drupal_get_path('module', $module)); - } + $cache = theme_get_registry(); // Check for correct content // @todo Remove this tests once double engine code is removed diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php index 7e95a03..d86920d 100644 --- a/core/modules/system/system.api.php +++ b/core/modules/system/system.api.php @@ -1806,21 +1806,13 @@ function hook_permission() { * - base hook: A string declaring the base theme hook if this theme * implementation is actually implementing a suggestion for another theme * hook. - * - pattern: A regular expression pattern to be used to allow this theme - * implementation to have a dynamic name. The convention is to use __ to - * differentiate the dynamic portion of the theme. For example, to allow - * forums to be themed individually, the pattern might be: 'forum__'. Then, - * when the forum is themed, call: - * @code - * theme(array('forum__' . $tid, 'forum'), $forum) - * @endcode * - preprocess functions: A list of functions used to preprocess this data. * Ordinarily this won't be used; it's automatically filled in. By default, * for a module this will be filled in as template_preprocess_HOOK. For * a theme this will be filled in as phptemplate_preprocess and * phptemplate_preprocess_HOOK as well as themename_preprocess and * themename_preprocess_HOOK. - * - override preprocess functions: Set to TRUE when a theme does NOT want + * - no preprocess: Set to TRUE when a theme does NOT want * the standard preprocess functions to run. This can be used to give a * theme FULL control over how variables are set. For example, if a theme * wants total control over how certain variables in the page.tpl.php are @@ -1866,8 +1858,9 @@ function hook_theme($existing, $type, $theme, $path) { * Changes here will not be visible until the next cache clear. * * The $theme_registry array is keyed by theme hook name, and contains the - * information returned from hook_theme(), as well as additional properties - * added by _theme_process_registry(). + * processed information returned from hook_theme(). + * + * @see \Drupal\Core\Theme\Registry::$registry * * For example: * @code @@ -1890,7 +1883,6 @@ function hook_theme($existing, $type, $theme, $path) { * The entire cache of theme registry information, post-processing. * * @see hook_theme() - * @see _theme_process_registry() */ function hook_theme_registry_alter(&$theme_registry) { // Kill the next/previous forum topic navigation links. diff --git a/core/modules/system/tests/modules/theme_test/theme_test.module b/core/modules/system/tests/modules/theme_test/theme_test.module index abd914f..d5f8cc6 100644 --- a/core/modules/system/tests/modules/theme_test/theme_test.module +++ b/core/modules/system/tests/modules/theme_test/theme_test.module @@ -97,19 +97,6 @@ function theme_test_init() { // 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) == 'user' && arg(1) == 'autocomplete') { - // 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()); - } -} - -/** - * Fake registry loading callback. - */ -function _theme_test_load_registry() { - print 'registry initialized'; - return array(); } /** diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php index a9d79ba..6851f70 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php @@ -7,6 +7,7 @@ namespace Drupal\views\Plugin\views\display; +use Drupal\Core\Theme\Registry; use Drupal\views\ViewExecutable; use \Drupal\views\Plugin\views\PluginBase; @@ -1765,7 +1766,7 @@ public function buildOptionsForm(&$form, &$form_state) { include_once DRUPAL_ROOT . '/' . $theme->owner; } } - $this->theme_registry = _theme_load_registry($theme, $base_theme, $theme_engine); + $this->theme_registry = new Registry($theme, $base_theme, $theme_engine); } // If there's a theme engine involved, we also need to know its extension