diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 3be853b..f2fb8a9 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -2603,6 +2603,8 @@ function drupal_common_theme() { 'task_list' => array( 'variables' => array('items' => NULL, 'active' => NULL, 'variant' => NULL), 'function' => 'theme_task_list', + 'path' => 'core/includes', + 'file' => 'theme.maintenance.inc', ), 'authorize_message' => array( 'variables' => array('message' => NULL, 'success' => TRUE), @@ -2621,6 +2623,8 @@ function drupal_common_theme() { 'menu_link' => array( 'render element' => 'element', 'function' => 'theme_menu_link', + 'path' => 'core/includes', + 'file' => 'menu.inc', ), 'menu_tree' => array( 'render element' => 'tree', diff --git a/core/lib/Drupal/Core/Template/TwigEnvironment.php b/core/lib/Drupal/Core/Template/TwigEnvironment.php index c671899..ae7179a 100644 --- a/core/lib/Drupal/Core/Template/TwigEnvironment.php +++ b/core/lib/Drupal/Core/Template/TwigEnvironment.php @@ -40,17 +40,19 @@ public function __construct(\Twig_LoaderInterface $loader = NULL, $options = arr // Set twig path namespace for themes and modules. $namespaces = array(); - foreach ($module_handler->getModuleList() as $name => $extension) { - $namespaces[$name] = $extension->getPath(); + foreach ($module_handler->getModuleList() as $extension) { + $namespaces[] = $extension->getPath(); } - foreach ($theme_handler->listInfo() as $name => $extension) { - $namespaces[$name] = $extension->getPath(); + foreach ($theme_handler->listInfo() as $extension) { + $namespaces[] = $extension->getPath(); } - foreach ($namespaces as $name => $path) { - $templatesDirectory = $path . '/templates'; - if (file_exists($templatesDirectory)) { - $loader->addPath($templatesDirectory, $name); + foreach ($namespaces as $path) { + $templates_dir = DRUPAL_ROOT . '/' . $path . '/templates'; + if (file_exists($templates_dir)) { + // We currently do not use namespaces in Twig. We must add all possible + // template directory paths to the __main__ namespace. + $loader->addPath($templates_dir); } } diff --git a/core/lib/Drupal/Core/Theme/Registry.php b/core/lib/Drupal/Core/Theme/Registry.php index 04e5882..abaad13 100644 --- a/core/lib/Drupal/Core/Theme/Registry.php +++ b/core/lib/Drupal/Core/Theme/Registry.php @@ -389,6 +389,9 @@ protected function build() { * @see _theme() * @see hook_theme() * @see list_themes() + * @see twig_render_template() + * + * @throws \BadFunctionCallException */ protected function processExtension(&$cache, $name, $type, $theme, $path) { $result = array(); @@ -418,12 +421,6 @@ protected function processExtension(&$cache, $name, $type, $theme, $path) { $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]['template'] = strtr($hook, '_', '-'); - } - if (isset($cache[$hook]['includes'])) { $result[$hook]['includes'] = $cache[$hook]['includes']; } @@ -439,20 +436,36 @@ protected function processExtension(&$cache, $name, $type, $theme, $path) { $result[$hook]['includes'][] = $include_file; } + // Templates are the default implementation for a theme hook. If a + // theme hook provides a theme function callback, it should only + // override existing template implementations. + if (isset($info['function'])) { + // Ensure theming function exists and remove any provided template. + if (function_exists($info['function'])) { + unset($result[$hook]['template']); + } + else { + throw new \BadFunctionCallException(sprintf( + 'Theme hook "%s" refers to a theme function callback that does not exist: "%s"', + $hook, + $info['function'] + )); + } + } + // Provide a default naming convention for 'template' based on the + // hook used. If the template does not exist, the template engine used + // (Twig) will throw throw an exception at runtime when attempting to + // include the template file (\Twig_Error_Loader). + elseif (!isset($info['template'])) { + $result[$hook]['template'] = strtr($hook, '_', '-'); + } + // If the default keys are not set, use the default values registered // by the module. if (isset($cache[$hook])) { $result[$hook] += array_intersect_key($cache[$hook], $hook_defaults); } - // 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']; - } - } - // Preprocess variables for all theming hooks, whether the hook is // implemented as a template or as a function. Ensure they are arrays. if (!isset($info['preprocess functions']) || !is_array($info['preprocess functions'])) { diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module index 2b838d6..db2d953 100644 --- a/core/modules/toolbar/toolbar.module +++ b/core/modules/toolbar/toolbar.module @@ -50,11 +50,9 @@ function toolbar_permission() { function toolbar_theme($existing, $type, $theme, $path) { $items['toolbar'] = array( 'render element' => 'element', - 'template' => 'toolbar', ); $items['toolbar_item'] = array( 'render element' => 'element', - 'function' => 'theme_toolbar_item', ); return $items; @@ -96,7 +94,7 @@ function toolbar_element_info() { // property contains a renderable array. $elements['toolbar_item'] = array( '#pre_render' => array('toolbar_pre_render_item'), - '#theme' => 'toolbar_item', + '#theme' => 'theme_toolbar_item', 'tab' => array( '#type' => 'link', '#title' => NULL, diff --git a/core/modules/views/views.module b/core/modules/views/views.module index 1acf4b5..59c5be9 100644 --- a/core/modules/views/views.module +++ b/core/modules/views/views.module @@ -121,8 +121,6 @@ function views_theme($existing, $type, $theme, $path) { // Our extra version of pager from pager.inc $hooks['views_mini_pager'] = $base + array( 'variables' => array('tags' => array(), 'quantity' => 10, 'element' => 0, 'parameters' => array()), - 'template' => 'views-mini-pager', - 'function' => 'theme_views_mini_pager', ); $variables = array( @@ -146,7 +144,6 @@ function views_theme($existing, $type, $theme, $path) { ); $hooks['views_view_grouping'] = $base + array( 'variables' => array('view' => NULL, 'grouping' => NULL, 'grouping_level' => NULL, 'rows' => NULL, 'title' => NULL), - 'template' => 'views-view-grouping', ); $plugins = Views::getPluginDefinitions(); @@ -202,8 +199,8 @@ function views_theme($existing, $type, $theme, $path) { // register_theme of the plugin to FALSE and implement hook_theme() by // itself. if (!function_exists('theme_' . $def['theme'])) { - $hooks[$def['theme']]['path'] = $module_dir; - $hooks[$def['theme']]['template'] = 'templates/' . drupal_clean_css_identifier($def['theme']); + $hooks[$def['theme']]['path'] = $module_dir . '/templates'; + $hooks[$def['theme']]['template'] = drupal_clean_css_identifier($def['theme']); } else { $hooks[$def['theme']]['function'] = 'theme_' . $def['theme']; @@ -213,17 +210,14 @@ function views_theme($existing, $type, $theme, $path) { $hooks['views_form_views_form'] = $base + array( 'render element' => 'form', - 'function' => 'theme_views_form_views_form', ); $hooks['views_exposed_form'] = $base + array( - 'template' => 'views-exposed-form', 'render element' => 'form', ); $hooks['views_more'] = $base + array( 'variables' => array('more_url' => NULL, 'link_text' => 'more', 'view' => NULL), - 'template' => 'views-more', ); return $hooks; diff --git a/core/themes/engines/twig/twig.engine b/core/themes/engines/twig/twig.engine index 1595bf8..b6d8fdb 100644 --- a/core/themes/engines/twig/twig.engine +++ b/core/themes/engines/twig/twig.engine @@ -36,22 +36,27 @@ function twig_init(Extension $theme) { * If the Twig debug setting is enabled, HTML comments including _theme() call * and template file name suggestions will surround the template markup. * - * @param $template_file + * @param string $template_file * The file name of the template to render. - * @param $variables + * @param array $variables * A keyed array of variables that will appear in the output. * - * @return + * @return string * The output generated by the template, plus any debug information. */ function twig_render_template($template_file, $variables) { $twig_service = \Drupal::service('twig'); - $output = array( - 'debug_prefix' => '', - 'debug_info' => '', - 'rendered_markup' => $twig_service->loadTemplate($template_file)->render($variables), - 'debug_suffix' => '', - ); + try { + $output = array( + 'debug_prefix' => '', + 'debug_info' => '', + 'rendered_markup' => $twig_service->loadTemplate($template_file)->render($variables), + 'debug_suffix' => '', + ); + } + catch (\Twig_Error_Loader $e) { + drupal_set_message($e->getMessage(), 'error'); + } if ($twig_service->isDebug()) { $output['debug_prefix'] .= "\n\n"; $output['debug_prefix'] .= "\n";