Issue #2173655 by Cottser, xjm, jessebeach, alexpott, rlmumford: Refactor theme() to _theme(); make it a private API to discourage module developers from circumventing the renderable build system.

8.0.x
Nathaniel Catchpole 2014-02-18 10:54:10 +00:00
parent 3b6b9774ec
commit a840af8381
29 changed files with 190 additions and 117 deletions

View File

@ -219,7 +219,8 @@ use Drupal\Component\Utility\Json;
* @code
* $commands = array();
* $commands[] = ajax_command_replace(NULL, $output);
* $commands[] = ajax_command_prepend(NULL, theme('status_messages'));
* $status_messages = array('#theme' => 'status_messages');
* $commands[] = ajax_command_prepend(NULL, drupal_render($status_messages));
* return array('#type' => 'ajax', '#commands' => $commands);
* @endcode
*

View File

@ -1376,7 +1376,7 @@ function base_path() {
* Adds a LINK tag with a distinct 'rel' attribute to the page's HEAD.
*
* This function can be called as long the HTML header hasn't been sent, which
* on normal pages is up through the preprocess step of theme('html'). Adding
* on normal pages is up through the preprocess step of _theme('html'). Adding
* a link will overwrite a prior link with the exact same 'rel' and 'href'
* attributes.
*
@ -2822,8 +2822,15 @@ function drupal_get_library($module, $name = NULL) {
* into a table. The table must have an ID attribute set. If using
* theme_table(), the ID may be set as follows:
* @code
* $output = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'my-module-table')));
* return $output;
* $table = array(
* '#type' => 'table',
* '#header' => $header,
* '#rows' => $rows,
* '#attributes' => array(
* 'id' => 'my-module-table',
* ),
* );
* return drupal_render($table);
* @endcode
*
* In the theme function for the form, a special class must be added to each
@ -3654,9 +3661,9 @@ function drupal_render_page($page) {
* $elements['#sorted'] = TRUE to avoid sorting them a second time.
* - The main render phase to produce #children for this element takes place:
* - If this element has #theme defined and #theme is an implemented theme
* hook/suggestion then theme() is called and must render both the element
* and its children. If #render_children is set, theme() will not be
* called. #render_children is usually only set internally by theme() so
* hook/suggestion then _theme() is called and must render both the element
* and its children. If #render_children is set, _theme() will not be
* called. #render_children is usually only set internally by _theme() so
* that we can avoid the situation where drupal_render() called from
* within a theme preprocess function creates an infinite loop.
* - If this element does not have a defined #theme, or the defined #theme
@ -3674,7 +3681,7 @@ function drupal_render_page($page) {
* drupal_process_attached().
* - If this element has an array of #theme_wrappers defined and
* #render_children is not set, #children is then re-rendered by passing the
* element in its current state to theme() successively for each item in
* element in its current state to _theme() successively for each item in
* #theme_wrappers. Since #theme and #theme_wrappers hooks often define
* variables with the same names it is possible to explicitly override each
* attribute passed to each #theme_wrappers hook by setting the hook name as
@ -3734,7 +3741,7 @@ function drupal_render_page($page) {
* The rendered HTML.
*
* @see element_info()
* @see theme()
* @see _theme()
* @see drupal_process_states()
* @see drupal_process_attached()
*/
@ -3807,11 +3814,11 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
// property is set, do not call the #theme function to prevent infinite
// recursion.
if ($theme_is_implemented && !isset($elements['#render_children'])) {
$elements['#children'] = theme($elements['#theme'], $elements);
$elements['#children'] = _theme($elements['#theme'], $elements);
// If theme() returns FALSE this means that the hook in #theme was not found
// in the registry and so we need to update our flag accordingly. This is
// common for theme suggestions.
// If _theme() returns FALSE this means that the hook in #theme was not
// found in the registry and so we need to update our flag accordingly. This
// is common for theme suggestions.
$theme_is_implemented = ($elements['#children'] !== FALSE);
}
@ -3854,7 +3861,7 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
// If the value of a #theme_wrappers item is an array then the theme hook
// is found in the key of the item and the value contains attribute
// overrides. Attribute overrides replace key/value pairs in $elements for
// only this theme() call. This allows #theme hooks and #theme_wrappers
// only this _theme() call. This allows #theme hooks and #theme_wrappers
// hooks to share variable names without conflict or ambiguity.
$wrapper_elements = $elements;
if (is_string($key)) {
@ -3867,7 +3874,7 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
$wrapper_hook = $value;
}
$elements['#children'] = theme($wrapper_hook, $wrapper_elements);
$elements['#children'] = _theme($wrapper_hook, $wrapper_elements);
}
}

View File

@ -36,10 +36,10 @@ function pager_find_page($element = 0) {
}
/**
* Initializes a pager for theme('pager').
* Initializes a pager for _theme('pager').
*
* This function sets up the necessary global variables so that future calls
* to theme('pager') will render a pager that correctly corresponds to the
* to _theme('pager') will render a pager that correctly corresponds to the
* items being displayed.
*
* If the items being displayed result from a database query performed using
@ -67,10 +67,14 @@ function pager_find_page($element = 0) {
* // Next, retrieve and display the items for the current page.
* $offset = $num_per_page * $page;
* $result = mymodule_select("SELECT * FROM data " . $where . " LIMIT %d, %d", $offset, $num_per_page)->fetchAll();
* $output = theme('mymodule_results', array('result' => $result));
* $output = drupal_render(
* '#theme' => 'mymodule_results',
* '#result' => $result,
* );
*
* // Finally, display the pager controls, and return.
* $output .= theme('pager');
* $pager = array('#theme' => 'pager');
* $output .= drupal_render($pager);
* return $output;
* @endcode
*
@ -93,10 +97,16 @@ function pager_find_page($element = 0) {
* pager_default_initialize($result->total, $num_per_page);
*
* // Display the search results.
* $output = theme('search_results', array('results' => $result->data, 'type' => 'remote'));
* $search_results = array(
* '#theme' => 'search_results',
* '#results' => $result->data,
* '#type' => 'remote',
* );
* $output = drupal_render($search_results);
*
* // Finally, display the pager controls, and return.
* $output .= theme('pager');
* $pager = array('#theme' => 'pager');
* $output .= drupal_render($pager);
* return $output;
* @endcode
*
@ -148,9 +158,9 @@ function pager_get_query_parameters() {
*
* Default template: pager.html.twig.
*
* Menu callbacks that display paged query results should call theme('pager') to
* retrieve a pager control so that users can view other results. Format a list
* of nearby pages with additional query results.
* Menu callbacks that display paged query results should call _theme('pager')
* to retrieve a pager control so that users can view other results. Format a
* list of nearby pages with additional query results.
*
* @param array $variables
* An associative array containing:

View File

@ -401,15 +401,15 @@ function drupal_find_base_themes($themes, $key) {
* Generates themed output.
*
* All requests for themed output must go through this function (however,
* calling the theme() function directly is strongly discouraged - see next
* paragraph). It examines the request and routes it to the appropriate
* calling the _theme() function directly is very strongly discouraged - see
* next paragraph). It examines the request and routes it to the appropriate
* @link themeable theme function or template @endlink, by checking the theme
* registry.
*
* Avoid calling this function directly. It is preferable to replace direct
* calls to the theme() function with calls to drupal_render() by passing a
* calls to the _theme() function with calls to drupal_render() by passing a
* render array with a #theme key to drupal_render(), which in turn calls
* theme().
* _theme().
*
* @section sec_theme_hooks Theme Hooks
* Most commonly, the first argument to this function is the name of the theme
@ -473,21 +473,21 @@ function drupal_find_base_themes($themes, $key) {
* hook_theme_suggestions_HOOK_alter() or the generic
* hook_theme_suggestions_alter(). These alter hooks are used to manipulate an
* array of suggested alternate theme hooks to use, in reverse order of
* priority. theme() will use the highest priority implementation that exists.
* If none exists, theme() will use the implementation for the theme hook it was
* called with. These suggestions are similar to and are used for similar
* reasons as calling theme() with an array as the $hook parameter (see below).
* priority. _theme() will use the highest priority implementation that exists.
* If none exists, _theme() will use the implementation for the theme hook it
* was called with. These suggestions are similar to and are used for similar
* reasons as calling _theme() with an array as the $hook parameter (see below).
* The difference is whether the suggestions are determined by the code that
* calls theme() or by altering the suggestions via the suggestion alter hooks.
* calls _theme() or by altering the suggestions via the suggestion alter hooks.
*
* @param $hook
* The name of the theme hook to call. If the name contains a
* double-underscore ('__') and there isn't an implementation for the full
* name, the part before the '__' is checked. This allows a fallback to a
* more generic implementation. For example, if theme('links__node', ...) is
* more generic implementation. For example, if _theme('links__node', ...) is
* called, but there is no implementation of that theme hook, then the
* 'links' implementation is used. This process is iterative, so if
* theme('links__contextual__node', ...) is called, theme() checks for the
* _theme('links__contextual__node', ...) is called, _theme() checks for the
* following implementations, and uses the first one that exists:
* - links__contextual__node
* - links__contextual
@ -495,7 +495,7 @@ function drupal_find_base_themes($themes, $key) {
* This allows themes to create specific theme implementations for named
* objects and contexts of otherwise generic theme hooks. The $hook parameter
* may also be an array, in which case the first theme hook that has an
* implementation is used. This allows for the code that calls theme() to
* implementation is used. This allows for the code that calls _theme() to
* explicitly specify the fallback order in a situation where using the '__'
* convention is not desired or is insufficient.
* @param $variables
@ -514,13 +514,13 @@ function drupal_find_base_themes($themes, $key) {
* @see hook_theme()
* @see template_preprocess()
*/
function theme($hook, $variables = array()) {
function _theme($hook, $variables = array()) {
static $default_attributes;
// 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 \Drupal\Core\Theme\Registry::get().
if (!\Drupal::moduleHandler()->isLoaded() && !defined('MAINTENANCE_MODE')) {
throw new Exception(t('theme() may not be called until all modules are loaded.'));
throw new Exception(t('_theme() may not be called until all modules are loaded.'));
}
/** @var \Drupal\Core\Utility\ThemeRegistry $theme_registry */
@ -558,7 +558,7 @@ function theme($hook, $variables = array()) {
watchdog('theme', 'Theme hook %hook not found.', array('%hook' => $hook), WATCHDOG_WARNING);
}
// There is no theme implementation for the hook passed. Return FALSE so
// the function calling theme() can differentiate between a hook that
// the function calling _theme() can differentiate between a hook that
// exists and renders an empty string and a hook that is not implemented.
return FALSE;
}
@ -622,7 +622,7 @@ function theme($hook, $variables = array()) {
// Invoke hook_theme_suggestions_HOOK().
$suggestions = Drupal::moduleHandler()->invokeAll('theme_suggestions_' . $base_theme_hook, array($variables));
// If theme() was invoked with a direct theme suggestion like
// If _theme() was invoked with a direct theme suggestion like
// '#theme' => 'node__article', add it to the suggestions array before
// invoking suggestion alter hooks.
if (isset($info['base hook'])) {
@ -638,8 +638,8 @@ function theme($hook, $variables = array()) {
\Drupal::moduleHandler()->alter($hooks, $suggestions, $variables, $base_theme_hook);
// Check if each suggestion exists in the theme registry, and if so,
// use it instead of the hook that theme() was called with. For example, a
// function may call theme('node', ...), but a module can add
// use it instead of the hook that _theme() was called with. For example, a
// function may call _theme('node', ...), but a module can add
// 'node__article' as a suggestion via hook_theme_suggestions_HOOK_alter(),
// enabling a theme to have an alternate template file for article nodes.
foreach (array_reverse($suggestions) as $suggestion) {
@ -1352,7 +1352,7 @@ function template_preprocess_links(&$variables) {
* to an empty string, but can be set to NULL for the attribute to be
* omitted. Usually, neither omission nor an empty string satisfies
* accessibility requirements, so it is strongly encouraged for code
* calling theme('image') to pass a meaningful value for this variable.
* calling _theme('image') to pass a meaningful value for this variable.
* - http://www.w3.org/TR/REC-html40/struct/objects.html#h-13.8
* - http://www.w3.org/TR/xhtml1/dtds.html
* - http://dev.w3.org/html5/spec/Overview.html#alt
@ -1956,10 +1956,10 @@ function _theme_table_cell($cell, $header = FALSE) {
* This function is called for theme hooks implemented as templates only, not
* for theme hooks implemented as functions. This preprocess function is the
* first in the sequence of preprocessing functions that are called when
* preparing variables for a template. See theme() for more details about the
* preparing variables for a template. See _theme() for more details about the
* full sequence.
*
* @see theme()
* @see _theme()
*/
function template_preprocess(&$variables, $hook, $info) {
// Tell all templates where they are located.
@ -2580,10 +2580,10 @@ function drupal_common_theme() {
// HTML 4 and XHTML 1.0 always require an alt attribute. The HTML 5 draft
// allows the alt attribute to be omitted in some cases. Therefore,
// default the alt attribute to an empty string, but allow code calling
// theme('image') to pass explicit NULL for it to be omitted. Usually,
// _theme('image') to pass explicit NULL for it to be omitted. Usually,
// neither omission nor an empty string satisfies accessibility
// requirements, so it is strongly encouraged for code calling
// theme('image') to pass a meaningful value for the alt variable.
// _theme('image') to pass a meaningful value for the alt variable.
// - http://www.w3.org/TR/REC-html40/struct/objects.html#h-13.8
// - http://www.w3.org/TR/xhtml1/dtds.html
// - http://dev.w3.org/html5/spec/Overview.html#alt

View File

@ -24,7 +24,7 @@ class UpdateModuleHandler extends ModuleHandler {
if (substr($hook, -6) === '_alter') {
return array();
}
// theme() is called during updates and fires hooks, so whitelist the
// _theme() is called during updates and fires hooks, so whitelist the
// system module.
if (substr($hook, 0, 6) == 'theme_') {
return array('system');

View File

@ -59,12 +59,12 @@ class Registry implements DestructableInterface {
* 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 effective path_to_theme() during theme(), available as
* - theme path: The effective path_to_theme() during _theme(), available as
* 'directory' variable in templates.
* functions, it should point to the respective theme. For templates,
* it should point to the directory that contains the template.
* - includes: (optional) An array of include files to load when the theme
* hook is executed by 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().
@ -291,7 +291,7 @@ class Registry implements DestructableInterface {
* 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 _theme()
* @see hook_theme_registry_alter()
*
* @return \Drupal\Core\Utility\ThemeRegistry
@ -374,7 +374,7 @@ class Registry implements DestructableInterface {
* 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.
* - 'preprocess functions': See _theme() for detailed documentation.
* @param string $name
* The name of the module, theme engine, base theme engine, theme or base
* theme implementing hook_theme().
@ -391,7 +391,7 @@ class Registry implements DestructableInterface {
* The directory where $name is. For example, modules/system or
* themes/bartik.
*
* @see theme()
* @see _theme()
* @see hook_theme()
* @see list_themes()
*/
@ -486,7 +486,7 @@ class Registry implements DestructableInterface {
}
foreach ($prefixes as $prefix) {
// Only use non-hook-specific variable preprocessors for theming
// hooks implemented as templates. See theme().
// hooks implemented as templates. See _theme().
if (isset($info['template']) && function_exists($prefix . '_preprocess')) {
$info['preprocess functions'][] = $prefix . '_preprocess';
}
@ -522,7 +522,7 @@ class Registry implements DestructableInterface {
$cache[$hook]['preprocess functions'] = array();
}
// Only use non-hook-specific variable preprocessors for theme hooks
// implemented as templates. See theme().
// implemented as templates. See _theme().
if (isset($info['template']) && function_exists($name . '_preprocess')) {
$cache[$hook]['preprocess functions'][] = $name . '_preprocess';
}

View File

@ -26,7 +26,7 @@ class ThemeRegistry extends CacheCollector implements DestructableInterface {
/**
* Whether the partial registry can be persisted to the cache.
*
* This is only allowed if all modules and the request method is GET. theme()
* This is only allowed if all modules and the request method is GET. _theme()
* should be very rarely called on POST requests and this avoids polluting
* the runtime cache.
*/

View File

@ -20,7 +20,7 @@
* If the module wishes to act on the rendered HTML of the block rather than
* the structured content array, it may use this hook to add a #post_render
* callback. Alternatively, it could also implement hook_preprocess_HOOK() for
* block.html.twig. See drupal_render() and theme() documentation respectively
* block.html.twig. See drupal_render() and _theme() documentation respectively
* for details.
*
* In addition to hook_block_view_alter(), which is called for all blocks, there

View File

@ -1395,7 +1395,6 @@ function template_preprocess_comment(&$variables) {
$variables['commented_entity'] = $commented_entity;
$account = comment_prepare_author($comment);
// @todo Do not call theme() here. We do this for purposes of t().
$username = array(
'#theme' => 'username',
'#account' => $account,
@ -1446,7 +1445,6 @@ function template_preprocess_comment(&$variables) {
$comment_parent = $comment->getParentComment();
$account_parent = comment_prepare_author($comment_parent);
$variables['parent_comment'] = $comment_parent;
// @todo Do not call theme() here. We do this for purposes of t().
$username = array(
'#theme' => 'username',
'#account' => $account_parent,

View File

@ -143,10 +143,10 @@ function image_theme() {
// HTML 4 and XHTML 1.0 always require an alt attribute. The HTML 5 draft
// allows the alt attribute to be omitted in some cases. Therefore,
// default the alt attribute to an empty string, but allow code calling
// theme('image_style') to pass explicit NULL for it to be omitted.
// _theme('image_style') to pass explicit NULL for it to be omitted.
// Usually, neither omission nor an empty string satisfies accessibility
// requirements, so it is strongly encouraged for code calling
// theme('image_style') to pass a meaningful value for the alt variable.
// _theme('image_style') to pass a meaningful value for the alt variable.
// - http://www.w3.org/TR/REC-html40/struct/objects.html#h-13.8
// - http://www.w3.org/TR/xhtml1/dtds.html
// - http://dev.w3.org/html5/spec/Overview.html#alt
@ -349,7 +349,7 @@ function image_style_options($include_empty = TRUE) {
* to an empty string, but can be set to NULL for the attribute to be
* omitted. Usually, neither omission nor an empty string satisfies
* accessibility requirements, so it is strongly encouraged for code calling
* theme('image_style') to pass a meaningful value for this variable.
* _theme('image_style') to pass a meaningful value for this variable.
* - http://www.w3.org/TR/REC-html40/struct/objects.html#h-13.8
* - http://www.w3.org/TR/xhtml1/dtds.html
* - http://dev.w3.org/html5/spec/Overview.html#alt

View File

@ -820,7 +820,7 @@ function hook_node_view(\Drupal\node\NodeInterface $node, \Drupal\Core\Entity\Di
* If the module wishes to act on the rendered HTML of the node rather than the
* structured content array, it may use this hook to add a #post_render
* callback. Alternatively, it could also implement hook_preprocess_HOOK() for
* node.html.twig. See drupal_render() and theme() documentation respectively
* node.html.twig. See drupal_render() and _theme() documentation respectively
* for details.
*
* @param $build

View File

@ -358,7 +358,7 @@ abstract class DrupalUnitTestBase extends UnitTestBase {
// Update the kernel to make their services available.
$this->kernel->updateModules($module_filenames, $module_filenames);
// Ensure isLoaded() is TRUE in order to make theme() work.
// Ensure isLoaded() is TRUE in order to make _theme() work.
// Note that the kernel has rebuilt the container; this $module_handler is
// no longer the $module_handler instance from above.
$module_handler = $this->container->get('module_handler');
@ -392,7 +392,7 @@ abstract class DrupalUnitTestBase extends UnitTestBase {
// Update the kernel to remove their services.
$this->kernel->updateModules($module_filenames, $module_filenames);
// Ensure isLoaded() is TRUE in order to make theme() work.
// Ensure isLoaded() is TRUE in order to make _theme() work.
// Note that the kernel has rebuilt the container; this $module_handler is
// no longer the $module_handler instance from above.
$module_handler = $this->container->get('module_handler');

View File

@ -249,7 +249,7 @@ class DrupalUnitTestBaseTest extends DrupalUnitTestBase {
}
/**
* Tests that theme() works right after loading a module.
* Tests that _theme() works right after loading a module.
*/
function testEnableModulesTheme() {
$original_element = $element = array(
@ -258,7 +258,7 @@ class DrupalUnitTestBaseTest extends DrupalUnitTestBase {
'#attributes' => array(),
);
$this->enableModules(array('system'));
// theme() throws an exception if modules are not loaded yet.
// _theme() throws an exception if modules are not loaded yet.
$this->assertTrue(drupal_render($element));
$element = $original_element;

View File

@ -2994,7 +2994,7 @@ abstract class WebTestBase extends TestBase {
* TRUE on pass, FALSE on fail.
*/
protected function assertThemeOutput($callback, array $variables = array(), $expected, $message = '', $group = 'Other') {
$output = theme($callback, $variables);
$output = _theme($callback, $variables);
$this->verbose('Variables:' . '<pre>' . check_plain(var_export($variables, TRUE)) . '</pre>'
. '<hr />' . 'Result:' . '<pre>' . check_plain(var_export($output, TRUE)) . '</pre>'
. '<hr />' . 'Expected:' . '<pre>' . check_plain(var_export($expected, TRUE)) . '</pre>'

View File

@ -477,7 +477,7 @@ function hook_entity_view(\Drupal\Core\Entity\EntityInterface $entity, \Drupal\C
* structured content array, it may use this hook to add a #post_render
* callback. Alternatively, it could also implement hook_preprocess_HOOK() for
* the particular entity type template, if there is one (e.g., node.html.twig).
* See drupal_render() and theme() for details.
* See drupal_render() and _theme() for details.
*
* @param $build
* A renderable array representing the entity content.

View File

@ -110,7 +110,11 @@ function callback_batch_finished($success, $results, $operations) {
$message = t("!count items were processed.", array(
'!count' => count($results),
));
$message .= theme('item_list', array('items' => $results));
$list = array(
'#theme' => 'item_list',
'#items' => $results,
);
$message .= drupal_render($list);
drupal_set_message($message);
}
else {

View File

@ -27,7 +27,13 @@ class TableTest extends WebTestBase {
function testThemeTableStickyHeaders() {
$header = array('one', 'two', 'three');
$rows = array(array(1,2,3), array(4,5,6), array(7,8,9));
$this->content = theme('table', array('header' => $header, 'rows' => $rows, 'sticky' => TRUE));
$table = array(
'#type' => 'table',
'#header' => $header,
'#rows' => $rows,
'#sticky' => TRUE,
);
$this->content = drupal_render($table);
$js = _drupal_add_js();
$this->assertTrue(isset($js['core/misc/tableheader.js']), 'tableheader.js was included when $sticky = TRUE.');
$this->assertRaw('sticky-enabled', 'Table has a class of sticky-enabled when $sticky = TRUE.');
@ -43,7 +49,16 @@ class TableTest extends WebTestBase {
$attributes = array();
$caption = NULL;
$colgroups = array();
$this->content = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => $attributes, 'caption' => $caption, 'colgroups' => $colgroups, 'sticky' => FALSE));
$table = array(
'#type' => 'table',
'#header' => $header,
'#rows' => $rows,
'#attributes' => $attributes,
'#caption' => $caption,
'#colgroups' => $colgroups,
'#sticky' => FALSE,
);
$this->content = drupal_render($table);
$js = _drupal_add_js();
$this->assertFalse(isset($js['core/misc/tableheader.js']), 'tableheader.js was not included because $sticky = FALSE.');
$this->assertNoRaw('sticky-enabled', 'Table does not have a class of sticky-enabled because $sticky = FALSE.');
@ -62,7 +77,13 @@ class TableTest extends WebTestBase {
'colspan' => 2,
),
);
$this->content = theme('table', array('header' => $header, 'rows' => array(), 'empty' => t('No strings available.')));
$table = array(
'#type' => 'table',
'#header' => $header,
'#rows' => array(),
'#empty' => t('No strings available.'),
);
$this->content = drupal_render($table);
$this->assertRaw('<tr class="odd"><td colspan="3" class="empty message">No strings available.</td>', 'Correct colspan was set on empty message.');
$this->assertRaw('<thead><tr><th>Header 1</th>', 'Table header was printed.');
}
@ -77,7 +98,11 @@ class TableTest extends WebTestBase {
'no_striping' => TRUE,
),
);
$this->content = theme('table', array('rows' => $rows));
$table = array(
'#type' => 'table',
'#rows' => $rows,
);
$this->content = drupal_render($table);
$this->assertNoRaw('class="odd"', 'Odd/even classes were not added because $no_striping = TRUE.');
$this->assertNoRaw('no_striping', 'No invalid no_striping HTML attribute was printed.');
}

View File

@ -41,7 +41,7 @@ class ThemeTest extends WebTestBase {
* Render arrays that use a render element and templates (and hence call
* template_preprocess()) must ensure the attributes at different occasions
* are all merged correctly:
* - $variables['attributes'] as passed in to theme()
* - $variables['attributes'] as passed in to _theme()
* - the render element's #attributes
* - any attributes set in the template's preprocessing function
*/
@ -58,21 +58,21 @@ class ThemeTest extends WebTestBase {
}
/**
* Test that theme() returns expected data types.
* Test that _theme() returns expected data types.
*/
function testThemeDataTypes() {
// theme_test_false is an implemented theme hook so theme() should return a
// theme_test_false is an implemented theme hook so _theme() should return a
// string, even though the theme function itself can return anything.
$foos = array('null' => NULL, 'false' => FALSE, 'integer' => 1, 'string' => 'foo');
foreach ($foos as $type => $example) {
$output = theme('theme_test_foo', array('foo' => $example));
$this->assertTrue(is_string($output), format_string('theme() returns a string for data type !type.', array('!type' => $type)));
$output = _theme('theme_test_foo', array('foo' => $example));
$this->assertTrue(is_string($output), format_string('_theme() returns a string for data type !type.', array('!type' => $type)));
}
// suggestionnotimplemented is not an implemented theme hook so theme()
// suggestionnotimplemented is not an implemented theme hook so _theme()
// should return FALSE instead of a string.
$output = theme(array('suggestionnotimplemented'));
$this->assertIdentical($output, FALSE, 'theme() returns FALSE when a hook suggestion is not implemented.');
$output = _theme(array('suggestionnotimplemented'));
$this->assertIdentical($output, FALSE, '_theme() returns FALSE when a hook suggestion is not implemented.');
}
/**

View File

@ -48,9 +48,9 @@ class TwigDebugMarkupTest extends WebTestBase {
// Create a node and test different features of the debug markup.
$node = $this->drupalCreateNode();
$output = theme('node', node_view($node));
$output = _theme('node', node_view($node));
$this->assertTrue(strpos($output, '<!-- THEME DEBUG -->') !== FALSE, 'Twig debug markup found in theme output when debug is enabled.');
$this->assertTrue(strpos($output, "CALL: theme('node')") !== FALSE, 'Theme call information found.');
$this->assertTrue(strpos($output, "CALL: _theme('node')") !== FALSE, 'Theme call information found.');
$this->assertTrue(strpos($output, 'x node--1' . $extension) !== FALSE, 'Node ID specific template shown as current template.');
$this->assertTrue(strpos($output, '* node' . $extension) !== FALSE, 'Base template file found.');
$template_filename = $templates['node__1']['path'] . '/' . $templates['node__1']['template'] . $extension;
@ -59,7 +59,7 @@ class TwigDebugMarkupTest extends WebTestBase {
// Create another node and make sure the template suggestions shown in the
// debug markup are correct.
$node2 = $this->drupalCreateNode();
$output = theme('node', node_view($node2));
$output = _theme('node', node_view($node2));
$this->assertTrue(strpos($output, '* node--2' . $extension) !== FALSE, 'Node ID specific template suggestion found.');
$this->assertTrue(strpos($output, 'x node' . $extension) !== FALSE, 'Base template file shown as current template.');
@ -68,7 +68,7 @@ class TwigDebugMarkupTest extends WebTestBase {
$this->rebuildContainer();
$this->resetAll();
$output = theme('node', node_view($node));
$output = _theme('node', node_view($node));
$this->assertFalse(strpos($output, '<!-- THEME DEBUG -->') !== FALSE, 'Twig debug markup not found in theme output when debug is disabled.');
}

View File

@ -1206,8 +1206,8 @@ function hook_permission() {
* - They can specify how a particular render array is to be rendered as HTML.
* This is usually the case if the theme function is assigned to the render
* array's #theme property.
* - They can return HTML for default calls to theme().
* - They can return HTML for calls to theme() for a theme suggestion.
* - They can return HTML for default calls to _theme().
* - They can return HTML for calls to _theme() for a theme suggestion.
*
* @param array $existing
* An array of existing implementations that may be used for override
@ -1234,18 +1234,18 @@ function hook_permission() {
* @return array
* An associative array of information about theme implementations. The keys
* on the outer array are known as "theme hooks". For simple theme
* implementations for regular calls to theme(), the theme hook is the first
* implementations for regular calls to _theme(), the theme hook is the first
* argument. For theme suggestions, instead of the array key being the base
* theme hook, the key is a theme suggestion name with the format
* 'base_hook_name__sub_hook_name'. For render elements, the key is the
* machine name of the render element. The array values are themselves arrays
* containing information about the theme hook and its implementation. Each
* information array must contain either a 'variables' element (for theme()
* information array must contain either a 'variables' element (for _theme()
* calls) or a 'render element' element (for render elements), but not both.
* The following elements may be part of each information array:
* - variables: Used for theme() call items only: an array of variables,
* - variables: Used for _theme() call items only: an array of variables,
* where the array keys are the names of the variables, and the array
* values are the default values if they are not passed into theme().
* values are the default values if they are not passed into _theme().
* Template implementations receive each array key as a variable in the
* template file (so they must be legal PHP/Twig variable names). Function
* implementations are passed the variables in a single $variables function
@ -1273,7 +1273,7 @@ function hook_permission() {
* registers the 'node' theme hook, 'theme_node' will be assigned to its
* function. If the chameleon theme registers the node hook, it will be
* assigned 'chameleon_node' as its function.
* - base hook: Used for theme() suggestions only: the base theme hook name.
* - base hook: Used for _theme() suggestions only: the base theme hook name.
* Instead of this suggestion's implementation being used directly, the base
* hook will be invoked with this implementation as its first suggestion.
* The base hook's files will be included and the base hook's preprocess
@ -1283,14 +1283,14 @@ function hook_permission() {
* suggestion may be used in place of this suggestion. If after
* hook_theme_suggestions_HOOK() this suggestion remains the first
* suggestion, then this suggestion's function or template will be used to
* generate the output for theme().
* generate the output for _theme().
* - 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)
* _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,

View File

@ -42,7 +42,12 @@ class ThemeTestSubscriber extends ContainerAware implements EventSubscriberInter
// theme_test_request_listener_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 a KernelEvents::REQUEST listener'));
$more_link = array(
'#theme' => 'more_link',
'#url' => 'user',
'#title' => 'Themed output generated in a KernelEvents::REQUEST listener',
);
$GLOBALS['theme_test_output'] = drupal_render($more_link);
}
}

View File

@ -55,7 +55,7 @@ class ThemeTestController extends ControllerBase {
* A render array containing a theme override.
*/
public function testTemplate() {
return theme('theme_test_template_test');
return _theme('theme_test_template_test');
}
/**
@ -65,12 +65,12 @@ class ThemeTestController extends ControllerBase {
* An HTML string containing the themed output.
*/
public function testSuggestion() {
return theme(array('theme_test__suggestion', 'theme_test'), array());
return _theme(array('theme_test__suggestion', 'theme_test'), array());
}
/**
* This is for testing that the theme can have hook_*_alter() implementations
* that run during page callback execution, even before theme() is called for
* that run during page callback execution, even before _theme() is called for
* the first time.
*
* @return string

View File

@ -102,14 +102,14 @@ function theme_test_page_alter(&$page) {
}
/**
* Theme function for testing theme('theme_test_foo').
* Theme function for testing _theme('theme_test_foo').
*/
function theme_theme_test_foo($variables) {
return $variables['foo'];
}
/**
* Theme function for testing theme('theme_test_function_template_override').
* Theme function for testing _theme('theme_test_function_template_override').
*/
function theme_theme_test_function_template_override($variables) {
return 'theme_test_function_template_override test failed.';
@ -132,8 +132,8 @@ function template_preprocess_theme_test_render_element(&$variables) {
* Theme function for testing rendering of child elements via drupal_render().
*
* Theme hooks defining a 'render element' add an internal '#render_children'
* property. When this property is found, drupal_render() avoids calling theme()
* on the top-level element to prevent infinite recursion.
* property. When this property is found, drupal_render() avoids calling
* _theme() on the top-level element to prevent infinite recursion.
*
* @param array $variables
* An associative array containing:

View File

@ -16,7 +16,7 @@ class TwigThemeTestController {
* Menu callback for testing PHP variables in a Twig template.
*/
public function phpVariablesRender() {
return theme('twig_theme_test_php_variables');
return _theme('twig_theme_test_php_variables');
}
/**

View File

@ -9,19 +9,41 @@
* layer. Each theme can take control over most of Drupal's output, and
* has complete control over the CSS.
*
* Inside Drupal, the theme layer is utilized by the use of the theme()
* Inside Drupal, the theme layer is utilized by the use of the _theme()
* function, which is passed the name of a component (the theme hook)
* and an array of variables. For example,
* theme('table', array('header' => $header, 'rows' => $rows));
* Additionally, the theme() function can take an array of theme
* _theme('table', array('header' => $header, 'rows' => $rows));
* Additionally, the _theme() function can take an array of theme
* hooks, which can be used to provide 'fallback' implementations to
* allow for more specific control of output. For example, the function:
* theme(array('table__foo', 'table'), $variables) would look to see if
* _theme(array('table__foo', 'table'), $variables) would look to see if
* 'table__foo' is registered anywhere; if it is not, it would 'fall back'
* to the generic 'table' implementation. This can be used to attach specific
* theme functions to named objects, allowing the themer more control over
* specific types of output.
*
* Calling the _theme() function directly is highly discouraged. Building a
* renderable array is preferred. For example, rather than calling
* _theme('table', array()) in-place, one can assemble a renderable array as
* follows:
*
* @code
* $table = array(
* '#type' => 'table',
* '#header' => '',
* '#rows' => array(),
* );
* @endcode
*
* Note that a table is defined as a type as well as a theme function. Building
* it as a type is preferred. The $table array can simply be passed along as
* a renderable array in a page build process. If necessary, the array may be
* rendered to a string by calling drupal_render().
*
* @code
* $output = drupal_render($table);
* @endcode
*
* As of Drupal 6, every theme hook is required to be registered by the
* module that owns it, so that Drupal can tell what to do with it and
* to make it simple for themes to identify and override the behavior
@ -55,10 +77,11 @@
*
* The theme system is described and defined in theme.inc.
*
* @see theme()
* @see _theme()
* @see hook_theme()
* @see hooks
* @see callbacks
* @see system_element_info()
*
* @} End of "defgroup themeable".
*/
@ -98,7 +121,7 @@ function hook_form_system_theme_settings_alter(&$form, &$form_state) {
* preprocess variables for a specific theme hook, whether implemented as a
* template or function.
*
* For more detailed information, see theme().
* For more detailed information, see _theme().
*
* @param $variables
* The variables array (modify in place).
@ -146,7 +169,7 @@ function hook_preprocess(&$variables, $hook) {
* hook. It should only be used if a module needs to override or add to the
* theme preprocessing for a theme hook it didn't define.
*
* For more detailed information, see theme().
* For more detailed information, see _theme().
*
* @param $variables
* The variables array (modify in place).

View File

@ -282,7 +282,7 @@ function hook_taxonomy_term_view(\Drupal\taxonomy\Entity\Term $term, \Drupal\Cor
* structured content array, it may use this hook to add a #post_render
* callback. Alternatively, it could also implement
* hook_preprocess_HOOK() for taxonomy-term.html.twig. See drupal_render() and
* theme() documentation respectively for details.
* _theme() documentation respectively for details.
*
* @param $build
* A renderable array representing the taxonomy term content.

View File

@ -178,9 +178,9 @@ function update_manager_update_form($form, $form_state = array(), $context) {
if ($needs_manual) {
// There are no checkboxes in the 'Manual updates' table so it will be
// rendered by theme('table'), not theme('tableselect'). Since the data
// rendered by _theme('table'), not _theme('tableselect'). Since the data
// formats are incompatible, we convert now to the format expected by
// theme('table').
// _theme('table').
unset($entry['#weight']);
$attributes = $entry['#attributes'];
unset($entry['#attributes']);

View File

@ -343,7 +343,7 @@ function hook_user_view(\Drupal\user\UserInterface $account, \Drupal\Core\Entity
* If the module wishes to act on the rendered HTML of the user rather than the
* structured content array, it may use this hook to add a #post_render callback.
* Alternatively, it could also implement hook_preprocess_HOOK() for
* user.html.twig. See drupal_render() and theme() documentation
* user.html.twig. See drupal_render() and _theme() documentation
* respectively for details.
*
* @param $build

View File

@ -35,7 +35,7 @@ function twig_init($template) {
/**
* Renders a Twig template.
*
* If the Twig debug setting is enabled, HTML comments including theme() call
* 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
@ -56,7 +56,7 @@ function twig_render_template($template_file, $variables) {
);
if (settings()->get('twig_debug', FALSE)) {
$output['debug_prefix'] .= "\n\n<!-- THEME DEBUG -->";
$output['debug_prefix'] .= "\n<!-- CALL: theme('{$variables['theme_hook_original']}') -->";
$output['debug_prefix'] .= "\n<!-- CALL: _theme('{$variables['theme_hook_original']}') -->";
if (!empty($variables['theme_hook_suggestions'])) {
$extension = twig_extension();
$current_template = basename($template_file);