177 lines
5.8 KiB
Plaintext
177 lines
5.8 KiB
Plaintext
|
<?php
|
||
|
|
||
|
/**
|
||
|
* @file
|
||
|
* Handles integration of Twig templates with the Drupal theme system.
|
||
|
*/
|
||
|
|
||
|
use Drupal\Component\Utility\SafeMarkup;
|
||
|
use Drupal\Core\Extension\Extension;
|
||
|
|
||
|
/**
|
||
|
* Implements hook_theme().
|
||
|
*/
|
||
|
function twig_theme($existing, $type, $theme, $path) {
|
||
|
$templates = drupal_find_theme_functions($existing, array($theme));
|
||
|
$templates += drupal_find_theme_templates($existing, '.html.twig', $path);
|
||
|
return $templates;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Implements hook_extension().
|
||
|
*/
|
||
|
function twig_extension() {
|
||
|
return '.html.twig';
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Implements hook_init().
|
||
|
*/
|
||
|
function twig_init(Extension $theme) {
|
||
|
$theme->load();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Implements hook_render_template().
|
||
|
*
|
||
|
* Renders a Twig template.
|
||
|
*
|
||
|
* If the Twig debug setting is enabled, HTML comments including _theme() call
|
||
|
* and template file name suggestions will surround the template markup.
|
||
|
*
|
||
|
* @param string $template_file
|
||
|
* The file name of the template to render.
|
||
|
* @param array $variables
|
||
|
* A keyed array of variables that will appear in the output.
|
||
|
*
|
||
|
* @return string
|
||
|
* The output generated by the template, plus any debug information.
|
||
|
*/
|
||
|
function twig_render_template($template_file, array $variables) {
|
||
|
/** @var \Twig_Environment $twig_service */
|
||
|
$twig_service = \Drupal::service('twig');
|
||
|
$output = [
|
||
|
'debug_prefix' => '',
|
||
|
'debug_info' => '',
|
||
|
'rendered_markup' => '',
|
||
|
'debug_suffix' => '',
|
||
|
];
|
||
|
try {
|
||
|
$output['rendered_markup'] = $twig_service->loadTemplate($template_file)->render($variables);
|
||
|
}
|
||
|
catch (\Twig_Error_Loader $e) {
|
||
|
drupal_set_message($e->getMessage(), 'error');
|
||
|
}
|
||
|
catch (\Twig_Error_Runtime $e) {
|
||
|
// In case there is a previous exception, re-throw the previous exception,
|
||
|
// so that the original exception is shown, rather than
|
||
|
// \Twig_Template::displayWithErrorHandling()'s exception.
|
||
|
$previous_exception = $e->getPrevious();
|
||
|
if ($previous_exception) {
|
||
|
throw $previous_exception;
|
||
|
}
|
||
|
throw $e;
|
||
|
}
|
||
|
if ($twig_service->isDebug()) {
|
||
|
$output['debug_prefix'] .= "\n\n<!-- THEME DEBUG -->";
|
||
|
$output['debug_prefix'] .= "\n<!-- THEME HOOK: '" . SafeMarkup::checkPlain($variables['theme_hook_original']) . "' -->";
|
||
|
// If there are theme suggestions, reverse the array so more specific
|
||
|
// suggestions are shown first.
|
||
|
if (!empty($variables['theme_hook_suggestions'])) {
|
||
|
$variables['theme_hook_suggestions'] = array_reverse($variables['theme_hook_suggestions']);
|
||
|
}
|
||
|
// Add debug output for directly called suggestions like
|
||
|
// '#theme' => 'comment__node__article'.
|
||
|
if (strpos($variables['theme_hook_original'], '__') !== FALSE) {
|
||
|
$derived_suggestions[] = $hook = $variables['theme_hook_original'];
|
||
|
while ($pos = strrpos($hook, '__')) {
|
||
|
$hook = substr($hook, 0, $pos);
|
||
|
$derived_suggestions[] = $hook;
|
||
|
}
|
||
|
// Get the value of the base hook (last derived suggestion) and append it
|
||
|
// to the end of all theme suggestions.
|
||
|
$base_hook = array_pop($derived_suggestions);
|
||
|
$variables['theme_hook_suggestions'] = array_merge($derived_suggestions, $variables['theme_hook_suggestions']);
|
||
|
$variables['theme_hook_suggestions'][] = $base_hook;
|
||
|
}
|
||
|
if (!empty($variables['theme_hook_suggestions'])) {
|
||
|
$extension = twig_extension();
|
||
|
$current_template = basename($template_file);
|
||
|
$suggestions = $variables['theme_hook_suggestions'];
|
||
|
// Only add the original theme hook if it wasn't a directly called
|
||
|
// suggestion.
|
||
|
if (strpos($variables['theme_hook_original'], '__') === FALSE) {
|
||
|
$suggestions[] = $variables['theme_hook_original'];
|
||
|
}
|
||
|
foreach ($suggestions as &$suggestion) {
|
||
|
$template = strtr($suggestion, '_', '-') . $extension;
|
||
|
$prefix = ($template == $current_template) ? 'x' : '*';
|
||
|
$suggestion = $prefix . ' ' . $template;
|
||
|
}
|
||
|
$output['debug_info'] .= "\n<!-- FILE NAME SUGGESTIONS:\n " . SafeMarkup::checkPlain(implode("\n ", $suggestions)) . "\n-->";
|
||
|
}
|
||
|
$output['debug_info'] .= "\n<!-- BEGIN OUTPUT from '" . SafeMarkup::checkPlain($template_file) . "' -->\n";
|
||
|
$output['debug_suffix'] .= "\n<!-- END OUTPUT from '" . SafeMarkup::checkPlain($template_file) . "' -->\n\n";
|
||
|
}
|
||
|
return SafeMarkup::set(implode('', $output));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Removes child elements from a copy of the original array.
|
||
|
*
|
||
|
* Creates a copy of the renderable array and removes child elements by key
|
||
|
* specified through filter's arguments. The copy can be printed without these
|
||
|
* elements. The original renderable array is still available and can be used
|
||
|
* to print child elements in their entirety in the twig template.
|
||
|
*
|
||
|
* @param array|object $element
|
||
|
* The parent renderable array to exclude the child items.
|
||
|
* @param string[] $args, ...
|
||
|
* The string keys of $element to prevent printing.
|
||
|
*
|
||
|
* @return array
|
||
|
* The filtered renderable array.
|
||
|
*/
|
||
|
function twig_without($element) {
|
||
|
if ($element instanceof ArrayAccess) {
|
||
|
$filtered_element = clone $element;
|
||
|
}
|
||
|
else {
|
||
|
$filtered_element = $element;
|
||
|
}
|
||
|
$args = func_get_args();
|
||
|
unset($args[0]);
|
||
|
foreach ($args as $arg) {
|
||
|
if (isset($filtered_element[$arg])) {
|
||
|
unset($filtered_element[$arg]);
|
||
|
}
|
||
|
}
|
||
|
return $filtered_element;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Overrides twig_join_filter().
|
||
|
*
|
||
|
* Safely joins several strings together.
|
||
|
*
|
||
|
* @param array|Traversable $value
|
||
|
* The pieces to join.
|
||
|
* @param string $glue
|
||
|
* The delimiter with which to join the string. Defaults to an empty string.
|
||
|
* This value is expected to be safe for output and user provided data should
|
||
|
* never be used as a glue.
|
||
|
*
|
||
|
* @return \Drupal\Component\Utility\SafeMarkup|string
|
||
|
* The imploded string, which is now also marked as safe.
|
||
|
*/
|
||
|
function twig_drupal_join_filter($value, $glue = '') {
|
||
|
$separator = '';
|
||
|
$output = '';
|
||
|
foreach ($value as $item) {
|
||
|
$output .= $separator . SafeMarkup::escape($item);
|
||
|
$separator = $glue;
|
||
|
}
|
||
|
|
||
|
return SafeMarkup::set($output);
|
||
|
}
|