Issue #3041076 by alexpott, shaal, Gábor Hojtsy, lauriii, Wim Leers, catch, Cottser, jibran, andypost, znerol, xim, joelpittet, effulgentsia: Update Drupal 9 to Twig 2

merge-requests/2419/head
Gábor Hojtsy 2019-10-31 13:39:18 +01:00
parent df84950d82
commit 5a143e77f9
55 changed files with 276 additions and 214 deletions

21
composer.lock generated
View File

@ -653,7 +653,7 @@
"dist": {
"type": "path",
"url": "core",
"reference": "9faae700fd9adfe0a1c5ffd73dcc334b3be5ce5a"
"reference": "ae05b62ba90c6bb364ba715d7005d99e188b8b85"
},
"require": {
"asm89/stack-cors": "^1.1",
@ -695,7 +695,7 @@
"symfony/translation": "^4.4",
"symfony/validator": "^4.4",
"symfony/yaml": "^4.4",
"twig/twig": "^1.38.2",
"twig/twig": "^2.12.0",
"typo3/phar-stream-wrapper": "^3.1.3",
"zendframework/zend-diactoros": "^1.8",
"zendframework/zend-feed": "^2.12"
@ -3472,21 +3472,22 @@
},
{
"name": "twig/twig",
"version": "v1.42.3",
"version": "v2.12.1",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "201baee843e0ffe8b0b956f336dd42b2a92fae4e"
"reference": "ddd4134af9bfc6dba4eff7c8447444ecc45b9ee5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/201baee843e0ffe8b0b956f336dd42b2a92fae4e",
"reference": "201baee843e0ffe8b0b956f336dd42b2a92fae4e",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/ddd4134af9bfc6dba4eff7c8447444ecc45b9ee5",
"reference": "ddd4134af9bfc6dba4eff7c8447444ecc45b9ee5",
"shasum": ""
},
"require": {
"php": ">=5.5.0",
"symfony/polyfill-ctype": "^1.8"
"php": "^7.0",
"symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.3"
},
"require-dev": {
"psr/container": "^1.0",
@ -3496,7 +3497,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.42-dev"
"dev-master": "2.12-dev"
}
},
"autoload": {
@ -3534,7 +3535,7 @@
"keywords": [
"templating"
],
"time": "2019-08-24T12:51:03+00:00"
"time": "2019-10-17T07:34:53+00:00"
},
{
"name": "typo3/phar-stream-wrapper",

View File

@ -59,7 +59,7 @@
"symfony/translation-contracts": "v1.1.7",
"symfony/validator": "4.4.x-dev",
"symfony/yaml": "4.4.x-dev",
"twig/twig": "v1.42.3",
"twig/twig": "v2.12.1",
"typo3/phar-stream-wrapper": "v3.1.3",
"zendframework/zend-diactoros": "1.8.7",
"zendframework/zend-escaper": "2.6.1",

View File

@ -32,7 +32,7 @@
"symfony/polyfill-iconv": "^1.0",
"symfony/yaml": "^4.4",
"typo3/phar-stream-wrapper": "^3.1.3",
"twig/twig": "^1.38.2",
"twig/twig": "^2.12.0",
"doctrine/common": "^2.7",
"doctrine/annotations": "^1.4",
"guzzlehttp/guzzle": "^6.3",

View File

@ -1643,11 +1643,11 @@ services:
# @todo Figure out what to do about debugging functions.
# @see https://www.drupal.org/node/1804998
twig.extension.debug:
class: Twig_Extension_Debug
class: Twig\Extension\DebugExtension
tags:
- { name: twig.extension }
twig.loader:
class: Twig_Loader_Chain
class: Twig\Loader\ChainLoader
public: false
tags:
- { name: service_collector, tag: twig.loader, call: addLoader, required: TRUE }

View File

@ -17,7 +17,7 @@ use Drupal\Component\Render\MarkupTrait;
* rendering.
*
* @see \Drupal\Core\Template\TwigExtension::escapeFilter
* @see \Twig_Markup
* @see \Twig\Markup
*/
final class Markup implements MarkupInterface, \Countable {
use MarkupTrait;

View File

@ -4,6 +4,7 @@ namespace Drupal\Core\Template\Loader;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Extension\ThemeHandlerInterface;
use Twig\Loader\FilesystemLoader as TwigFilesystemLoader;
/**
* Loads templates from the filesystem.
@ -12,7 +13,7 @@ use Drupal\Core\Extension\ThemeHandlerInterface;
* filesystem loader so that templates can be referenced by namespace, like
* @block/block.html.twig or @mytheme/page.html.twig.
*/
class FilesystemLoader extends \Twig_Loader_Filesystem {
class FilesystemLoader extends TwigFilesystemLoader {
/**
* Constructs a new FilesystemLoader object.

View File

@ -2,7 +2,7 @@
namespace Drupal\Core\Template\Loader;
use Twig\Loader\ExistsLoaderInterface;
use Twig\Loader\LoaderInterface;
use Twig\Loader\SourceContextLoaderInterface;
use Twig\Source;
@ -18,13 +18,13 @@ use Twig\Source;
* This class override ensures that the string loader behaves as expected in
* the loader chain. If Twig's string loader is used as is, any string (even a
* reference to a file-based Twig template) is treated as a valid template and
* is rendered instead of a \Twig_Error_Loader exception being thrown.
* is rendered instead of a \Twig\Error\LoaderError exception being thrown.
*
* @see \Drupal\Core\Template\TwigEnvironment::renderInline()
* @see \Drupal\Core\Render\Element\InlineTemplate
* @see twig_render_template()
*/
class StringLoader implements \Twig_LoaderInterface, ExistsLoaderInterface, SourceContextLoaderInterface {
class StringLoader implements LoaderInterface, SourceContextLoaderInterface {
/**
* {@inheritdoc}

View File

@ -3,13 +3,15 @@
namespace Drupal\Core\Template\Loader;
use Drupal\Core\Theme\Registry;
use Twig\Error\LoaderError;
use Twig\Loader\FilesystemLoader;
/**
* Loads templates based on information from the Drupal theme registry.
*
* Allows for template inheritance based on the currently active template.
*/
class ThemeRegistryLoader extends \Twig_Loader_Filesystem {
class ThemeRegistryLoader extends FilesystemLoader {
/**
* The theme registry used to determine which template to use.
@ -39,7 +41,7 @@ class ThemeRegistryLoader extends \Twig_Loader_Filesystem {
* @return string|false
* The path to the template, or false if the template is not found.
*
* @throws \Twig_Error_Loader
* @throws \Twig\Error\LoaderError
* Thrown if a template matching $name cannot be found.
*/
protected function findTemplate($name, $throw = TRUE) {
@ -61,7 +63,7 @@ class ThemeRegistryLoader extends \Twig_Loader_Filesystem {
}
if ($throw) {
throw new \Twig_Error_Loader(sprintf('Unable to find template "%s" in the Drupal theme registry.', $name));
throw new LoaderError(sprintf('Unable to find template "%s" in the Drupal theme registry.', $name));
}
return FALSE;

View File

@ -6,16 +6,17 @@ use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\PhpStorage\PhpStorageFactory;
use Drupal\Core\Render\Markup;
use Drupal\Core\State\StateInterface;
use Twig\Environment;
use Twig\Extension\SandboxExtension;
use Twig\Loader\LoaderInterface;
/**
* A class that defines a Twig environment for Drupal.
*
* Instances of this class are used to store the configuration and extensions,
* and are used to load templates from the file system or other locations.
*
* @see core\vendor\twig\twig\lib\Twig\Environment.php
*/
class TwigEnvironment extends \Twig_Environment {
class TwigEnvironment extends Environment {
/**
* Key name of the Twig cache prefix metadata key-value pair in State.
@ -55,12 +56,12 @@ class TwigEnvironment extends \Twig_Environment {
* The Twig extension hash.
* @param \Drupal\Core\State\StateInterface $state
* The state service.
* @param \Twig_LoaderInterface $loader
* @param \Twig\Loader\LoaderInterface $loader
* The Twig loader or loader chain.
* @param array $options
* The options for the Twig environment.
*/
public function __construct($root, CacheBackendInterface $cache, $twig_extension_hash, StateInterface $state, \Twig_LoaderInterface $loader = NULL, array $options = []) {
public function __construct($root, CacheBackendInterface $cache, $twig_extension_hash, StateInterface $state, LoaderInterface $loader = NULL, array $options = []) {
$this->state = $state;
// Ensure that twig.engine is loaded, given that it is needed to render a
@ -97,7 +98,7 @@ class TwigEnvironment extends \Twig_Environment {
$this->setLoader($loader);
parent::__construct($this->getLoader(), $options);
$policy = new TwigSandboxPolicy();
$sandbox = new \Twig_Extension_Sandbox($policy, TRUE);
$sandbox = new SandboxExtension($policy, TRUE);
$this->addExtension($sandbox);
}

View File

@ -14,6 +14,14 @@ use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Routing\UrlGeneratorInterface;
use Drupal\Core\Theme\ThemeManagerInterface;
use Drupal\Core\Url;
use Twig\Environment;
use Twig\Extension\AbstractExtension;
use Twig\Markup as TwigMarkup;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Node;
use Twig\TwigFilter;
use Twig\TwigFunction;
/**
* A class providing Drupal Twig extensions.
@ -23,7 +31,7 @@ use Drupal\Core\Url;
*
* @see \Drupal\Core\CoreServiceProvider
*/
class TwigExtension extends \Twig_Extension {
class TwigExtension extends AbstractExtension {
/**
* The URL generator.
@ -137,19 +145,19 @@ class TwigExtension extends \Twig_Extension {
public function getFunctions() {
return [
// This function will receive a renderable array, if an array is detected.
new \Twig_SimpleFunction('render_var', [$this, 'renderVar']),
new TwigFunction('render_var', [$this, 'renderVar']),
// The url and path function are defined in close parallel to those found
// in \Symfony\Bridge\Twig\Extension\RoutingExtension
new \Twig_SimpleFunction('url', [$this, 'getUrl'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']]),
new \Twig_SimpleFunction('path', [$this, 'getPath'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']]),
new \Twig_SimpleFunction('link', [$this, 'getLink']),
new \Twig_SimpleFunction('file_url', function ($uri) {
new TwigFunction('url', [$this, 'getUrl'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']]),
new TwigFunction('path', [$this, 'getPath'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']]),
new TwigFunction('link', [$this, 'getLink']),
new TwigFunction('file_url', function ($uri) {
return file_url_transform_relative(file_create_url($uri));
}),
new \Twig_SimpleFunction('attach_library', [$this, 'attachLibrary']),
new \Twig_SimpleFunction('active_theme_path', [$this, 'getActiveThemePath']),
new \Twig_SimpleFunction('active_theme', [$this, 'getActiveTheme']),
new \Twig_SimpleFunction('create_attribute', [$this, 'createAttribute']),
new TwigFunction('attach_library', [$this, 'attachLibrary']),
new TwigFunction('active_theme_path', [$this, 'getActiveThemePath']),
new TwigFunction('active_theme', [$this, 'getActiveTheme']),
new TwigFunction('create_attribute', [$this, 'createAttribute']),
];
}
@ -159,32 +167,32 @@ class TwigExtension extends \Twig_Extension {
public function getFilters() {
return [
// Translation filters.
new \Twig_SimpleFilter('t', 't', ['is_safe' => ['html']]),
new \Twig_SimpleFilter('trans', 't', ['is_safe' => ['html']]),
new TwigFilter('t', 't', ['is_safe' => ['html']]),
new TwigFilter('trans', 't', ['is_safe' => ['html']]),
// The "raw" filter is not detectable when parsing "trans" tags. To detect
// which prefix must be used for translation (@, !, %), we must clone the
// "raw" filter and give it identifiable names. These filters should only
// be used in "trans" tags.
// @see TwigNodeTrans::compileString()
new \Twig_SimpleFilter('placeholder', [$this, 'escapePlaceholder'], ['is_safe' => ['html'], 'needs_environment' => TRUE]),
new TwigFilter('placeholder', [$this, 'escapePlaceholder'], ['is_safe' => ['html'], 'needs_environment' => TRUE]),
// Replace twig's escape filter with our own.
new \Twig_SimpleFilter('drupal_escape', [$this, 'escapeFilter'], ['needs_environment' => TRUE, 'is_safe_callback' => 'twig_escape_filter_is_safe']),
new TwigFilter('drupal_escape', [$this, 'escapeFilter'], ['needs_environment' => TRUE, 'is_safe_callback' => 'twig_escape_filter_is_safe']),
// Implements safe joining.
// @todo Make that the default for |join? Upstream issue:
// https://github.com/fabpot/Twig/issues/1420
new \Twig_SimpleFilter('safe_join', [$this, 'safeJoin'], ['needs_environment' => TRUE, 'is_safe' => ['html']]),
new TwigFilter('safe_join', [$this, 'safeJoin'], ['needs_environment' => TRUE, 'is_safe' => ['html']]),
// Array filters.
new \Twig_SimpleFilter('without', [$this, 'withoutFilter']),
new TwigFilter('without', [$this, 'withoutFilter']),
// CSS class and ID filters.
new \Twig_SimpleFilter('clean_class', '\Drupal\Component\Utility\Html::getClass'),
new \Twig_SimpleFilter('clean_id', '\Drupal\Component\Utility\Html::getId'),
new TwigFilter('clean_class', '\Drupal\Component\Utility\Html::getClass'),
new TwigFilter('clean_id', '\Drupal\Component\Utility\Html::getId'),
// This filter will render a renderable array to use the string results.
new \Twig_SimpleFilter('render', [$this, 'renderVar']),
new \Twig_SimpleFilter('format_date', [$this->dateFormatter, 'format']),
new TwigFilter('render', [$this, 'renderVar']),
new TwigFilter('format_date', [$this->dateFormatter, 'format']),
];
}
@ -299,7 +307,7 @@ class TwigExtension extends \Twig_Extension {
}
// The text has been processed by twig already, convert it to a safe object
// for the render system.
if ($text instanceof \Twig_Markup) {
if ($text instanceof TwigMarkup) {
$text = Markup::create($text);
}
$build = [
@ -351,18 +359,18 @@ class TwigExtension extends \Twig_Extension {
* If param1 and param2 reference placeholders in the route, it would not
* need to be escaped, but we don't know that in advance.
*
* @param \Twig_Node $args_node
* @param \Twig\Node\Node $args_node
* The arguments of the path/url functions.
*
* @return array
* An array with the contexts the URL is safe
*/
public function isUrlGenerationSafe(\Twig_Node $args_node) {
public function isUrlGenerationSafe(Node $args_node) {
// Support named arguments.
$parameter_node = $args_node->hasNode('parameters') ? $args_node->getNode('parameters') : ($args_node->hasNode(1) ? $args_node->getNode(1) : NULL);
if (!isset($parameter_node) || $parameter_node instanceof \Twig_Node_Expression_Array && count($parameter_node) <= 2 &&
(!$parameter_node->hasNode(1) || $parameter_node->getNode(1) instanceof \Twig_Node_Expression_Constant)) {
if (!isset($parameter_node) || $parameter_node instanceof ArrayExpression && count($parameter_node) <= 2 &&
(!$parameter_node->hasNode(1) || $parameter_node->getNode(1) instanceof ConstantExpression)) {
return ['html'];
}
@ -392,15 +400,15 @@ class TwigExtension extends \Twig_Extension {
/**
* Provides a placeholder wrapper around ::escapeFilter.
*
* @param \Twig_Environment $env
* A Twig_Environment instance.
* @param \Twig\Environment $env
* A Twig Environment instance.
* @param mixed $string
* The value to be escaped.
*
* @return string|null
* The escaped, rendered output, or NULL if there is no valid output.
*/
public function escapePlaceholder(\Twig_Environment $env, $string) {
public function escapePlaceholder(Environment $env, $string) {
$return = $this->escapeFilter($env, $string);
return $return ? '<em class="placeholder">' . $return . '</em>' : NULL;
@ -414,8 +422,8 @@ class TwigExtension extends \Twig_Extension {
* Note: This function should be kept in sync with
* theme_render_and_autoescape().
*
* @param \Twig_Environment $env
* A Twig_Environment instance.
* @param \Twig\Environment $env
* A Twig Environment instance.
* @param mixed $arg
* The value to be escaped.
* @param string $strategy
@ -436,7 +444,7 @@ class TwigExtension extends \Twig_Extension {
* @todo Refactor this to keep it in sync with theme_render_and_autoescape()
* in https://www.drupal.org/node/2575065
*/
public function escapeFilter(\Twig_Environment $env, $arg, $strategy = 'html', $charset = NULL, $autoescape = FALSE) {
public function escapeFilter(Environment $env, $arg, $strategy = 'html', $charset = NULL, $autoescape = FALSE) {
// Check for a numeric zero int or float.
if ($arg === 0 || $arg === 0.0) {
return 0;
@ -449,8 +457,8 @@ class TwigExtension extends \Twig_Extension {
$this->bubbleArgMetadata($arg);
// Keep Twig_Markup objects intact to support autoescaping.
if ($autoescape && ($arg instanceof \Twig_Markup || $arg instanceof MarkupInterface)) {
// Keep \Twig\Markup objects intact to support autoescaping.
if ($autoescape && ($arg instanceof TwigMarkup || $arg instanceof MarkupInterface)) {
return $arg;
}
@ -538,7 +546,7 @@ class TwigExtension extends \Twig_Extension {
* If an object is passed which does not implement __toString(),
* RenderableInterface or toString() then an exception is thrown;
* Other objects are casted to string. However in the case that the
* object is an instance of a Twig_Markup object it is returned directly
* object is an instance of a \Twig\Markup object it is returned directly
* to support auto escaping.
*
* If an array is passed it is rendered via render() and scalar values are
@ -552,7 +560,7 @@ class TwigExtension extends \Twig_Extension {
* RenderableInterface or toString().
*
* @return mixed
* The rendered output or an Twig_Markup object.
* The rendered output or an \Twig\Markup object.
*
* @see render
* @see TwigNodeVisitor
@ -604,8 +612,8 @@ class TwigExtension extends \Twig_Extension {
/**
* Joins several strings together safely.
*
* @param \Twig_Environment $env
* A Twig_Environment instance.
* @param \Twig\Environment $env
* A Twig Environment instance.
* @param mixed[]|\Traversable|null $value
* The pieces to join.
* @param string $glue
@ -616,7 +624,7 @@ class TwigExtension extends \Twig_Extension {
* @return string
* The strings joined together.
*/
public function safeJoin(\Twig_Environment $env, $value, $glue = '') {
public function safeJoin(Environment $env, $value, $glue = '') {
if ($value instanceof \Traversable) {
$value = iterator_to_array($value, FALSE);
}

View File

@ -2,7 +2,18 @@
namespace Drupal\Core\Template;
use Twig\Compiler;
use Twig\Error\SyntaxError;
use Twig\Node\CheckToStringNode;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\FilterExpression;
use Twig\Node\Expression\FunctionExpression;
use Twig\Node\Expression\GetAttrExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Node\Expression\TempNameExpression;
use Twig\Node\Node;
use Twig\Node\PrintNode;
/**
* A class that defines the Twig 'trans' tag for Drupal.
@ -14,12 +25,12 @@ use Twig\Node\CheckToStringNode;
* @see https://twig-extensions.readthedocs.io/en/latest/i18n.html
* @see https://github.com/fabpot/Twig-extensions
*/
class TwigNodeTrans extends \Twig_Node {
class TwigNodeTrans extends Node {
/**
* {@inheritdoc}
*/
public function __construct(\Twig_Node $body, \Twig_Node $plural = NULL, \Twig_Node_Expression $count = NULL, \Twig_Node_Expression $options = NULL, $lineno, $tag = NULL) {
public function __construct(Node $body, Node $plural = NULL, AbstractExpression $count = NULL, AbstractExpression $options = NULL, $lineno, $tag = NULL) {
$nodes['body'] = $body;
if ($count !== NULL) {
$nodes['count'] = $count;
@ -36,7 +47,7 @@ class TwigNodeTrans extends \Twig_Node {
/**
* {@inheritdoc}
*/
public function compile(\Twig_Compiler $compiler) {
public function compile(Compiler $compiler) {
$compiler->addDebugInfo($this);
list($singular, $tokens) = $this->compileString($this->getNode('body'));
@ -88,7 +99,7 @@ class TwigNodeTrans extends \Twig_Node {
/**
* Extracts the text and tokens for the "trans" tag.
*
* @param \Twig_Node $body
* @param \Twig\Node\Node $body
* The node to compile.
*
* @return array
@ -96,10 +107,11 @@ class TwigNodeTrans extends \Twig_Node {
* - string $text
* The extracted text.
* - array $tokens
* The extracted tokens as new \Twig_Node_Expression_Name instances.
* The extracted tokens as new \Twig\Node\Expression\TempNameExpression
* instances.
*/
protected function compileString(\Twig_Node $body) {
if ($body instanceof \Twig_Node_Expression_Name || $body instanceof \Twig_Node_Expression_Constant || $body instanceof \Twig_Node_Expression_TempName) {
protected function compileString(Node $body) {
if ($body instanceof NameExpression || $body instanceof ConstantExpression || $body instanceof TempNameExpression) {
return [$body, []];
}
@ -108,13 +120,9 @@ class TwigNodeTrans extends \Twig_Node {
$text = '';
foreach ($body as $node) {
if (get_class($node) === 'Twig_Node' && $node->getNode(0) instanceof \Twig_Node_SetTemp) {
$node = $node->getNode(1);
}
if ($node instanceof \Twig_Node_Print) {
if ($node instanceof PrintNode) {
$n = $node->getNode('expr');
while ($n instanceof \Twig_Node_Expression_Filter) {
while ($n instanceof FilterExpression) {
$n = $n->getNode('node');
}
@ -124,7 +132,7 @@ class TwigNodeTrans extends \Twig_Node {
$args = $n;
// Support TwigExtension->renderVar() function in chain.
if ($args instanceof \Twig_Node_Expression_Function) {
if ($args instanceof FunctionExpression) {
$args = $n->getNode('arguments')->getNode(0);
}
@ -134,7 +142,7 @@ class TwigNodeTrans extends \Twig_Node {
// safe for templates.
// @see TwigExtension::getFilters()
$argPrefix = '@';
while ($args instanceof \Twig_Node_Expression_Filter) {
while ($args instanceof FilterExpression) {
switch ($args->getNode('filter')->getAttribute('value')) {
case 'placeholder':
$argPrefix = '%';
@ -145,7 +153,7 @@ class TwigNodeTrans extends \Twig_Node {
if ($args instanceof CheckToStringNode) {
$args = $args->getNode('expr');
}
if ($args instanceof \Twig_Node_Expression_GetAttr) {
if ($args instanceof GetAttrExpression) {
$argName = [];
// Reuse the incoming expression.
$expr = $args;
@ -153,7 +161,7 @@ class TwigNodeTrans extends \Twig_Node {
$argName[] = $args->getNode('attribute')->getAttribute('value');
while ($args->hasNode('node')) {
$args = $args->getNode('node');
if ($args instanceof \Twig_Node_Expression_Name) {
if ($args instanceof NameExpression) {
$argName[] = $args->getAttribute('name');
}
else {
@ -168,7 +176,7 @@ class TwigNodeTrans extends \Twig_Node {
if (!is_null($args)) {
$argName = $args->getAttribute('name');
}
$expr = new \Twig_Node_Expression_Name($argName, $n->getTemplateLine());
$expr = new NameExpression($argName, $n->getTemplateLine());
}
$placeholder = sprintf('%s%s', $argPrefix, $argName);
$text .= $placeholder;
@ -181,14 +189,14 @@ class TwigNodeTrans extends \Twig_Node {
}
}
elseif (!$body->hasAttribute('data')) {
throw new \Twig_Error_Syntax('{% trans %} tag cannot be empty');
throw new SyntaxError('{% trans %} tag cannot be empty');
}
else {
$text = $body->getAttribute('data');
}
return [
new \Twig_Node([new \Twig_Node_Expression_Constant(trim($text), $body->getTemplateLine())]),
new Node([new ConstantExpression(trim($text), $body->getTemplateLine())]),
$tokens,
];
}

View File

@ -2,8 +2,15 @@
namespace Drupal\Core\Template;
use Twig\Environment;
use Twig\Node\Expression\FilterExpression;
use Twig\Node\Expression\FunctionExpression;
use Twig\Node\Node;
use Twig\Node\PrintNode;
use Twig\NodeVisitor\AbstractNodeVisitor;
/**
* Provides a Twig_NodeVisitor to change the generated parse-tree.
* Provides a TwigNodeVisitor to change the generated parse-tree.
*
* This is used to ensure that everything printed is wrapped via the
* TwigExtension->renderVar() function in order to just write {{ content }}
@ -11,22 +18,22 @@ namespace Drupal\Core\Template;
*
* @see twig_render
*/
class TwigNodeVisitor extends \Twig_BaseNodeVisitor {
class TwigNodeVisitor extends AbstractNodeVisitor {
/**
* {@inheritdoc}
*/
protected function doEnterNode(\Twig_Node $node, \Twig_Environment $env) {
protected function doEnterNode(Node $node, Environment $env) {
return $node;
}
/**
* {@inheritdoc}
*/
protected function doLeaveNode(\Twig_Node $node, \Twig_Environment $env) {
protected function doLeaveNode(Node $node, Environment $env) {
// We use this to inject a call to render_var -> TwigExtension->renderVar()
// before anything is printed.
if ($node instanceof \Twig_Node_Print) {
if ($node instanceof PrintNode) {
if (!empty($this->skipRenderVarFunction)) {
// No need to add the callback, we have escape active already.
unset($this->skipRenderVarFunction);
@ -35,12 +42,12 @@ class TwigNodeVisitor extends \Twig_BaseNodeVisitor {
$class = get_class($node);
$line = $node->getTemplateLine();
return new $class(
new \Twig_Node_Expression_Function('render_var', new \Twig_Node([$node->getNode('expr')]), $line),
new FunctionExpression('render_var', new Node([$node->getNode('expr')]), $line),
$line
);
}
// Change the 'escape' filter to our own 'drupal_escape' filter.
elseif ($node instanceof \Twig_Node_Expression_Filter) {
elseif ($node instanceof FilterExpression) {
$name = $node->getNode('filter')->getAttribute('value');
if ('escape' == $name || 'e' == $name) {
// Use our own escape filter that is MarkupInterface aware.

View File

@ -5,6 +5,7 @@ namespace Drupal\Core\Template;
use Drupal\Component\Utility\Crypt;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\PhpStorage\PhpStorageFactory;
use Twig\Cache\CacheInterface;
/**
* Provides an alternate cache storage for Twig using PhpStorage.
@ -16,7 +17,7 @@ use Drupal\Core\PhpStorage\PhpStorageFactory;
*
* @see \Drupal\Core\DependencyInjection\Compiler\TwigExtensionPass
*/
class TwigPhpStorageCache implements \Twig_CacheInterface {
class TwigPhpStorageCache implements CacheInterface {
/**
* The maximum length for each part of the cache key suffix.

View File

@ -3,6 +3,8 @@
namespace Drupal\Core\Template;
use Drupal\Core\Site\Settings;
use Twig\Sandbox\SecurityError;
use Twig\Sandbox\SecurityPolicyInterface;
/**
* Default sandbox policy for Twig templates.
@ -13,7 +15,7 @@ use Drupal\Core\Site\Settings;
* objects can do by whitelisting certain classes, method names, and method
* names with an allowed prefix. All object properties may be accessed.
*/
class TwigSandboxPolicy implements \Twig_Sandbox_SecurityPolicyInterface {
class TwigSandboxPolicy implements SecurityPolicyInterface {
/**
* An array of whitelisted methods in the form of methodName => TRUE.
@ -102,7 +104,7 @@ class TwigSandboxPolicy implements \Twig_Sandbox_SecurityPolicyInterface {
}
}
throw new \Twig_Sandbox_SecurityError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, get_class($obj)));
throw new SecurityError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, get_class($obj)));
}
}

View File

@ -2,6 +2,16 @@
namespace Drupal\Core\Template;
use Twig\Error\SyntaxError;
use Twig\Node\Expression\FilterExpression;
use Twig\Node\Expression\GetAttrExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Node\Node;
use Twig\Node\PrintNode;
use Twig\Node\TextNode;
use Twig\Token;
use Twig\TokenParser\AbstractTokenParser;
/**
* A class that defines the Twig 'trans' token parser for Drupal.
*
@ -9,16 +19,15 @@ namespace Drupal\Core\Template;
* code into an Abstract Syntax Tree (AST). The AST will later be compiled
* into PHP code usable for runtime execution of the template.
*
* @see \Twig_TokenParser
* @see https://twig-extensions.readthedocs.io/en/latest/i18n.html
* @see https://github.com/fabpot/Twig-extensions
*/
class TwigTransTokenParser extends \Twig_TokenParser {
class TwigTransTokenParser extends AbstractTokenParser {
/**
* {@inheritdoc}
*/
public function parse(\Twig_Token $token) {
public function parse(Token $token) {
$lineno = $token->getLine();
$stream = $this->parser->getStream();
$body = NULL;
@ -26,24 +35,24 @@ class TwigTransTokenParser extends \Twig_TokenParser {
$count = NULL;
$plural = NULL;
if (!$stream->test(\Twig_Token::BLOCK_END_TYPE) && $stream->test(\Twig_Token::STRING_TYPE)) {
if (!$stream->test(Token::BLOCK_END_TYPE) && $stream->test(Token::STRING_TYPE)) {
$body = $this->parser->getExpressionParser()->parseExpression();
}
if (!$stream->test(\Twig_Token::BLOCK_END_TYPE) && $stream->test(\Twig_Token::NAME_TYPE, 'with')) {
if (!$stream->test(Token::BLOCK_END_TYPE) && $stream->test(Token::NAME_TYPE, 'with')) {
$stream->next();
$options = $this->parser->getExpressionParser()->parseExpression();
}
if (!$body) {
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
$stream->expect(Token::BLOCK_END_TYPE);
$body = $this->parser->subparse([$this, 'decideForFork']);
if ('plural' === $stream->next()->getValue()) {
$count = $this->parser->getExpressionParser()->parseExpression();
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
$stream->expect(Token::BLOCK_END_TYPE);
$plural = $this->parser->subparse([$this, 'decideForEnd'], TRUE);
}
}
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
$stream->expect(Token::BLOCK_END_TYPE);
$this->checkTransString($body, $lineno);
@ -76,27 +85,27 @@ class TwigTransTokenParser extends \Twig_TokenParser {
/**
* Ensure that any nodes that are parsed are only of allowed types.
*
* @param \Twig_Node $body
* @param \Twig\Node\Node $body
* The expression to check.
* @param int $lineno
* The source line.
*
* @throws \Twig_Error_Syntax
* @throws \Twig\Error\SyntaxError
*/
protected function checkTransString(\Twig_Node $body, $lineno) {
protected function checkTransString(Node $body, $lineno) {
foreach ($body as $node) {
if (
$node instanceof \Twig_Node_Text
$node instanceof TextNode
||
($node instanceof \Twig_Node_Print && $node->getNode('expr') instanceof \Twig_Node_Expression_Name)
($node instanceof PrintNode && $node->getNode('expr') instanceof NameExpression)
||
($node instanceof \Twig_Node_Print && $node->getNode('expr') instanceof \Twig_Node_Expression_GetAttr)
($node instanceof PrintNode && $node->getNode('expr') instanceof GetAttrExpression)
||
($node instanceof \Twig_Node_Print && $node->getNode('expr') instanceof \Twig_Node_Expression_Filter)
($node instanceof PrintNode && $node->getNode('expr') instanceof FilterExpression)
) {
continue;
}
throw new \Twig_Error_Syntax(sprintf('The text to be translated with "trans" can only contain references to simple variables'), $lineno);
throw new SyntaxError(sprintf('The text to be translated with "trans" can only contain references to simple variables'), $lineno);
}
}

View File

@ -14,11 +14,11 @@
* @ingroup themeable
*/
#}
{% spaceless %}
{% apply spaceless %}
<dl>
{% for type in types %}
<dt>{{ type.link }}</dt>
<dd>{{ type.description }}</dd>
{% endfor %}
</dl>
{% endspaceless %}
{% endapply %}

View File

@ -36,12 +36,12 @@
to be exported as printer-friendly HTML.
#}
{% for i in 1..depth-1 if depth > 1 %}
{% if depth > 1 %}{% for i in 1..depth-1 %}
<div>
{% endfor %}
{% endfor %}{% endif %}
{{ contents }}
{% for i in 1..depth-1 if depth > 1 %}
{% if depth > 1 %}{% for i in 1..depth-1 %}
</div>
{% endfor %}
{% endfor %}{% endif %}
</body>
</html>

View File

@ -13,7 +13,7 @@
* @ingroup themeable
*/
#}
{% spaceless %}
{% apply spaceless %}
<fieldset role="form" aria-labelledby="ckeditor-button-configuration ckeditor-button-description">
<legend id="ckeditor-button-configuration">{{ 'Toolbar configuration'|t }}</legend>
<div class="fieldset-wrapper">
@ -72,4 +72,4 @@
</div>
</div>
</fieldset>
{% endspaceless %}
{% endapply %}

View File

@ -50,7 +50,7 @@
depth this forum resides at. This will allow us to use CSS
left-margin for indenting.
#}
{% for i in 1..forum.depth if forum.depth > 0 %}<div class="indent">{% endfor %}
{% if forum.depth > 0 %}{% for i in 1..forum.depth %}<div class="indent">{% endfor %}{% endif %}
<div title="{{ forum.icon_title }}">
<span class="visually-hidden">{{ forum.icon_title }}</span>
</div>
@ -58,7 +58,7 @@
{% if forum.description.value %}
<div>{{ forum.description.value }}</div>
{% endif %}
{% for i in 1..forum.depth if forum.depth > 0 %}</div>{% endfor %}
{% if forum.depth > 0 %}{% for i in 1..forum.depth %}</div>{% endfor %}{% endif %}
</td>
{% if forum.is_container == false %}
<td>

View File

@ -7,6 +7,7 @@ use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Extension\ThemeHandlerInterface;
use Drupal\Core\Serialization\Yaml;
use Twig\Error\LoaderError;
use Twig\Loader\FilesystemLoader;
use Twig\Source;
/**
@ -24,7 +25,7 @@ use Twig\Source;
* experimental modules and development releases of contributed modules.
* See https://www.drupal.org/core/experimental for more information.
*/
class HelpTopicTwigLoader extends \Twig_Loader_Filesystem {
class HelpTopicTwigLoader extends FilesystemLoader {
/**
* {@inheritdoc}

View File

@ -104,7 +104,7 @@ class HelpTopicTwigTest extends UnitTestCase {
}
/**
* Defines a fake template class to mock \Twig_TemplateWrapper.
* Defines a fake template class to mock \Twig\TemplateWrapper.
*
* We cannot use getMockBuilder() for this, because the Twig TemplateWrapper
* class is declared "final" and cannot be mocked.
@ -129,7 +129,7 @@ class FakeTemplateWrapper {
}
/**
* Mocks the \Twig_TemplateWrapper render() method.
* Mocks the \Twig\TemplateWrapper render() method.
*
* @param array $context
* (optional) Render context.

View File

@ -14,7 +14,7 @@
* @ingroup themeable
*/
#}
{% spaceless %}
{% apply spaceless %}
{{ title }}
{{ link }}
{% endspaceless %}
{% endapply %}

View File

@ -12,11 +12,11 @@
*/
#}
{% if children %}
{% spaceless %}
{% apply spaceless %}
<div class="dropbutton-wrapper">
<div class="dropbutton-widget">
{{ children }}
</div>
</div>
{% endspaceless %}
{% endapply %}
{% endif %}

View File

@ -11,4 +11,4 @@
* @ingroup themeable
*/
#}
{% for i in 1..size if size > 0 %}<div class="js-indentation indentation">&nbsp;</div>{% endfor %}
{% if size > 0 %}{% for i in 1..size %}<div class="js-indentation indentation">&nbsp;</div>{% endfor %}{% endif %}

View File

@ -12,7 +12,7 @@
* @ingroup themeable
*/
#}
{% spaceless %}
{% apply spaceless %}
<select{{ attributes }}>
{% for option in options %}
{% if option.type == 'optgroup' %}
@ -26,4 +26,4 @@
{% endif %}
{% endfor %}
</select>
{% endspaceless %}
{% endapply %}

View File

@ -2,13 +2,14 @@
namespace Drupal\twig_extension_test\TwigExtension;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
/**
* A test Twig extension that adds a custom function and a custom filter.
*/
class TestExtension extends \Twig_Extension {
class TestExtension extends AbstractExtension {
/**
* Generates a list of all Twig functions that this extension defines.

View File

@ -2,12 +2,15 @@
namespace Drupal\twig_loader_test\Loader;
use Twig\Loader\ExistsLoaderInterface;
use Twig\Loader\LoaderInterface;
use Twig\Loader\SourceContextLoaderInterface;
use Twig\Source;
/**
* A test Twig loader.
*/
class TestLoader implements \Twig_LoaderInterface, \Twig_ExistsLoaderInterface, \Twig_SourceContextLoaderInterface {
class TestLoader implements LoaderInterface, ExistsLoaderInterface, SourceContextLoaderInterface {
/**
* {@inheritdoc}

View File

@ -4,6 +4,7 @@ namespace Drupal\Tests\system\Functional\Theme;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Tests\BrowserTestBase;
use Twig\Error\SyntaxError;
/**
* Tests Twig "trans" tags.
@ -107,7 +108,7 @@ class TwigTransTest extends BrowserTestBase {
$this->fail('{% trans %}{% endtrans %} did not throw an exception.');
}
catch (\Twig_Error_Syntax $e) {
catch (SyntaxError $e) {
$this->assertTrue(strstr($e->getMessage(), '{% trans %} tag cannot be empty'), '{% trans %}{% endtrans %} threw the expected exception.');
}
catch (\Exception $e) {

View File

@ -29,7 +29,7 @@
{% set tray = trays[key] %}
<div{{ tab.attributes.addClass('toolbar-tab') }}>
{{ tab.link }}
{% spaceless %}
{% apply spaceless %}
<div{{ tray.attributes }}>
{% if tray.label %}
<nav class="toolbar-lining clearfix" role="navigation" aria-label="{{ tray.label }}">
@ -40,7 +40,7 @@
{{ tray.links }}
</nav>
</div>
{% endspaceless %}
{% endapply %}
</div>
{% endfor %}
</nav>

View File

@ -13,6 +13,7 @@ use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\views\Render\ViewsRenderPipelineMarkup;
use Drupal\views\ResultRow;
use Drupal\views\ViewExecutable;
use Twig\Environment;
/**
* @defgroup views_field_handlers Views field handler plugins
@ -726,7 +727,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
'#default_value' => $this->options['alter']['text'],
// The tag list will be escaped.
'#description' => $this->t('The text to display for this field. You may enter data from this view as per the "Replacement patterns" below. You may include <a href="@twig_docs">Twig</a> or the following allowed HTML tags: <code>@tags</code>', [
'@twig_docs' => 'https://twig.symfony.com/doc/' . \Twig_Environment::MAJOR_VERSION . '.x',
'@twig_docs' => 'https://twig.symfony.com/doc/' . Environment::MAJOR_VERSION . '.x',
'@tags' => '<' . implode('> <', Xss::getAdminTagList()) . '>',
]),
'#states' => [

View File

@ -9,6 +9,8 @@ use Drupal\Core\Site\Settings;
use Drupal\Core\Template\TwigPhpStorageCache;
use Drupal\KernelTests\KernelTestBase;
use Symfony\Component\DependencyInjection\Definition;
use Twig\Environment;
use Twig\Error\LoaderError;
/**
* Tests the twig environment.
@ -106,7 +108,7 @@ class TwigEnvironmentTest extends KernelTestBase {
$environment->loadTemplate('this-template-does-not-exist.html.twig')->render([]);
$this->fail('Did not throw an exception as expected.');
}
catch (\Twig_Error_Loader $e) {
catch (LoaderError $e) {
$this->assertTrue(strpos($e->getMessage(), 'Template "this-template-does-not-exist.html.twig" is not defined') === 0);
}
}
@ -184,7 +186,7 @@ class TwigEnvironmentTest extends KernelTestBase {
public function register(ContainerBuilder $container) {
parent::register($container);
$container->setDefinition('twig_loader__file_system', new Definition('Twig_Loader_Filesystem', [[sys_get_temp_dir()]]))
$container->setDefinition('twig_loader__file_system', new Definition('Twig\Loader\FilesystemLoader', [[sys_get_temp_dir()]]))
->addTag('twig.loader');
}
@ -216,7 +218,7 @@ TWIG;
// Manually change $templateClassPrefix to force a different template
// classname, as the other class is still loaded. This wouldn't be a problem
// on a real site where you reload the page.
$reflection = new \ReflectionClass(\Twig_Environment::class);
$reflection = new \ReflectionClass(Environment::class);
$property_reflection = $reflection->getProperty('templateClassPrefix');
$property_reflection->setAccessible(TRUE);
$property_reflection->setValue($environment, 'otherPrefix');

View File

@ -10,6 +10,7 @@ use Drupal\Core\Template\AttributeString;
use Drupal\Core\Template\Loader\StringLoader;
use Drupal\Tests\UnitTestCase;
use Drupal\Component\Render\MarkupInterface;
use Twig\Environment;
/**
* @coversDefaultClass \Drupal\Core\Template\Attribute
@ -265,7 +266,7 @@ class AttributeTest extends UnitTestCase {
*/
public function testTwigAddRemoveClasses($template, $expected, $seed_attributes = []) {
$loader = new StringLoader();
$twig = new \Twig_Environment($loader);
$twig = new Environment($loader);
$data = ['attributes' => new Attribute($seed_attributes)];
$result = $twig->createTemplate($template)->render($data);
$this->assertEquals($expected, $result);

View File

@ -10,6 +10,11 @@ use Drupal\Core\Template\TwigEnvironment;
use Drupal\Core\Template\TwigExtension;
use Drupal\Core\Url;
use Drupal\Tests\UnitTestCase;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use Twig\Loader\FilesystemLoader;
use Twig\Node\Expression\FilterExpression;
use Twig\Source;
/**
* Tests the twig extension.
@ -75,8 +80,8 @@ class TwigExtensionTest extends UnitTestCase {
* @dataProvider providerTestEscaping
*/
public function testEscaping($template, $expected) {
$loader = new \Twig_Loader_Filesystem();
$twig = new \Twig_Environment($loader, [
$loader = new FilesystemLoader();
$twig = new Environment($loader, [
'debug' => TRUE,
'cache' => FALSE,
'autoescape' => 'html',
@ -85,11 +90,11 @@ class TwigExtensionTest extends UnitTestCase {
$twig->addExtension($this->systemUnderTest);
$name = '__string_template_test__';
$nodes = $twig->parse($twig->tokenize(new \Twig_Source($template, $name)));
$nodes = $twig->parse($twig->tokenize(new Source($template, $name)));
$this->assertSame($expected, $nodes->getNode('body')
->getNode(0)
->getNode('expr') instanceof \Twig_Node_Expression_Filter);
->getNode('expr') instanceof FilterExpression);
}
/**
@ -138,7 +143,7 @@ class TwigExtensionTest extends UnitTestCase {
->willReturn($active_theme);
$loader = new StringLoader();
$twig = new \Twig_Environment($loader);
$twig = new Environment($loader);
$twig->addExtension($this->systemUnderTest);
$result = $twig->render('{{ active_theme() }}');
$this->assertEquals('test_theme', $result);
@ -155,7 +160,7 @@ class TwigExtensionTest extends UnitTestCase {
}));
$loader = new StringLoader();
$twig = new \Twig_Environment($loader);
$twig = new Environment($loader);
$twig->addExtension($this->systemUnderTest);
$timestamp = strtotime('1978-11-19');
$result = $twig->render('{{ time|format_date("html_date") }}', ['time' => $timestamp]);
@ -178,7 +183,7 @@ class TwigExtensionTest extends UnitTestCase {
->willReturn($active_theme);
$loader = new StringLoader();
$twig = new \Twig_Environment($loader);
$twig = new Environment($loader);
$twig->addExtension($this->systemUnderTest);
$result = $twig->render('{{ active_theme_path() }}');
$this->assertEquals('foo/bar', $result);
@ -190,8 +195,8 @@ class TwigExtensionTest extends UnitTestCase {
* @covers ::escapeFilter
*/
public function testSafeStringEscaping() {
$loader = new \Twig_Loader_Filesystem();
$twig = new \Twig_Environment($loader, [
$loader = new FilesystemLoader();
$twig = new Environment($loader, [
'debug' => TRUE,
'cache' => FALSE,
'autoescape' => 'html',
@ -275,8 +280,8 @@ class TwigExtensionTest extends UnitTestCase {
* @covers ::bubbleArgMetadata
*/
public function testEscapeWithGeneratedLink() {
$loader = new \Twig_Loader_Filesystem();
$twig = new \Twig_Environment($loader, [
$loader = new FilesystemLoader();
$twig = new Environment($loader, [
'debug' => TRUE,
'cache' => FALSE,
'autoescape' => 'html',
@ -335,8 +340,8 @@ class TwigExtensionTest extends UnitTestCase {
*/
public function testCreateAttribute() {
$name = '__string_template_test_1__';
$loader = new \Twig_Loader_Array([$name => "{% for iteration in iterations %}<div{{ create_attribute(iteration) }}></div>{% endfor %}"]);
$twig = new \Twig_Environment($loader);
$loader = new ArrayLoader([$name => "{% for iteration in iterations %}<div{{ create_attribute(iteration) }}></div>{% endfor %}"]);
$twig = new Environment($loader);
$twig->addExtension($this->systemUnderTest);
$iterations = [
@ -350,7 +355,7 @@ class TwigExtensionTest extends UnitTestCase {
// Test default creation of empty attribute object and using its method.
$name = '__string_template_test_2__';
$loader = new \Twig_Loader_Array([$name => "<div{{ create_attribute().addClass('meow') }}></div>"]);
$loader = new ArrayLoader([$name => "<div{{ create_attribute().addClass('meow') }}></div>"]);
$twig->setLoader($loader);
$result = $twig->render($name);
$expected = '<div class="meow"></div>';

View File

@ -11,6 +11,9 @@ use Drupal\Core\Template\Attribute;
use Drupal\Core\Template\TwigSandboxPolicy;
use Drupal\Core\Template\Loader\StringLoader;
use Drupal\Tests\UnitTestCase;
use Twig\Environment;
use Twig\Extension\SandboxExtension;
use Twig\Sandbox\SecurityError;
/**
* Tests the twig sandbox policy.
@ -24,7 +27,7 @@ class TwigSandboxTest extends UnitTestCase {
/**
* The Twig environment loaded with the sandbox extension.
*
* @var \Twig_Environment
* @var \Twig\Environment
*/
protected $twig;
@ -35,9 +38,9 @@ class TwigSandboxTest extends UnitTestCase {
parent::setUp();
$loader = new StringLoader();
$this->twig = new \Twig_Environment($loader);
$this->twig = new Environment($loader);
$policy = new TwigSandboxPolicy();
$sandbox = new \Twig_Extension_Sandbox($policy, TRUE);
$sandbox = new SandboxExtension($policy, TRUE);
$this->twig->addExtension($sandbox);
}
@ -48,7 +51,7 @@ class TwigSandboxTest extends UnitTestCase {
*/
public function testEntityDangerousMethods($template) {
$entity = $this->createMock('Drupal\Core\Entity\EntityInterface');
$this->expectException(\Twig_Sandbox_SecurityError::class);
$this->expectException(SecurityError::class);
$this->twig->render($template, ['entity' => $entity]);
}

View File

@ -193,6 +193,9 @@ trait DeprecationListenerTrait {
'The "core/matchmedia" asset library is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. See https://www.drupal.org/node/3086653',
'The "core/matchmedia.addListener" asset library is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. See https://www.drupal.org/node/3086653',
'The "core/classList" asset library is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the the native browser implementation instead. See https://www.drupal.org/node/3089511',
// The following deprecation is listed for Twig 2 compatibility when unit
// testing using \Symfony\Component\ErrorHandler\DebugClassLoader.
'The "Twig\Environment::getTemplateClass()" method is considered internal. It may change without further notice. You should not extend it from "Drupal\Core\Template\TwigEnvironment".',
];
}

View File

@ -9,7 +9,7 @@
* - size: Optional. The number of indentations to create.
*/
#}
{% for i in 1..size if size > 0 %}<div class="js-indentation indentation">
{% if size > 0 %}{% for i in 1..size %}<div class="js-indentation indentation">
<svg
xmlns="http://www.w3.org/2000/svg"
class="tree"
@ -33,4 +33,4 @@
d="M12.5,12 v99"
stroke="#888"/>
</svg>
</div>{% endfor %}
</div>{% endfor %}{% endif %}

View File

@ -11,7 +11,7 @@
* @see claro_preprocess_input()
*/
#}
{% spaceless %}
{% apply spaceless %}
{% if autocomplete_message %}
<div class="claro-autocomplete">
<input{{ attributes }}/>
@ -21,4 +21,4 @@
{% else %}
<input{{ attributes }}/>{{ children }}
{% endif %}
{% endspaceless %}
{% endapply %}

View File

@ -40,7 +40,7 @@
<ul class="pager__items js-pager__items">
{# Print first item if we are not on the first page. #}
{% if items.first %}
{% spaceless %}
{% apply spaceless %}
<li class="pager__item pager__item--action pager__item--first">
<a href="{{ items.first.href }}" class="pager__link pager__link--action-link" title="{{ 'Go to first page'|t }}"{{ items.first.attributes|without('href', 'title') }}>
<span class="visually-hidden">{{ 'First page'|t }}</span>
@ -49,12 +49,12 @@
</span>
</a>
</li>
{% endspaceless %}
{% endapply %}
{% endif %}
{# Print previous item if we are not on the first page. #}
{% if items.previous %}
{% spaceless %}
{% apply spaceless %}
<li class="pager__item pager__item--action pager__item--previous">
<a href="{{ items.previous.href }}" class="pager__link pager__link--action-link" title="{{ 'Go to previous page'|t }}" rel="prev"{{ items.previous.attributes|without('href', 'title', 'rel') }}>
<span class="visually-hidden">{{ 'Previous page'|t }}</span>
@ -63,7 +63,7 @@
</span>
</a>
</li>
{% endspaceless %}
{% endapply %}
{% endif %}
{# Add an ellipsis if there are further previous pages. #}
@ -73,7 +73,7 @@
{# Now generate the actual pager piece. #}
{% for key, item in items.pages %}
{% spaceless %}
{% apply spaceless %}
<li class="pager__item{{ current == key ? ' pager__item--active' : '' }} pager__item--number">
{% if current == key %}
{% set title = 'Current page'|t %}
@ -87,7 +87,7 @@
{{ key }}
</a>
</li>
{% endspaceless %}
{% endapply %}
{% endfor %}
{# Add an ellipsis if there are further next pages. #}
@ -97,7 +97,7 @@
{# Print next item if we are not on the last page. #}
{% if items.next %}
{% spaceless %}
{% apply spaceless %}
<li class="pager__item pager__item--action pager__item--next">
<a href="{{ items.next.href }}" class="pager__link pager__link--action-link" title="{{ 'Go to next page'|t }}" rel="next"{{ items.next.attributes|without('href', 'title', 'rel') }}>
<span class="visually-hidden">{{ 'Next page'|t }}</span>
@ -106,12 +106,12 @@
</span>
</a>
</li>
{% endspaceless %}
{% endapply %}
{% endif %}
{# Print last item if we are not on the last page. #}
{% if items.last %}
{% spaceless %}
{% apply spaceless %}
<li class="pager__item pager__item--action pager__item--last">
<a href="{{ items.last.href }}" class="pager__link pager__link--action-link" title="{{ 'Go to last page'|t }}"{{ items.last.attributes|without('href', 'title') }}>
<span class="visually-hidden">{{ 'Last page'|t }}</span>
@ -120,7 +120,7 @@
</span>
</a>
</li>
{% endspaceless %}
{% endapply %}
{% endif %}
</ul>
</nav>

View File

@ -22,13 +22,13 @@
<h4{{ title_attributes.addClass('visually-hidden').setAttribute('id', heading_id) }}>{{ 'Pagination'|t }}</h4>
<ul{{ content_attributes.addClass('pager__items', 'js-pager__items') }}>
{% if items.previous %}
{% spaceless %}
{% apply spaceless %}
<li class="pager__item pager__item--mini pager__item--action pager__item--previous">
<a{{ items.previous.attributes.addClass(pager_action_classes).setAttribute('title', 'Go to previous page'|t).setAttribute('href', items.previous.href) }}>
<span class="visually-hidden">{{ 'Previous page'|t }}</span>
</a>
</li>
{% endspaceless %}
{% endapply %}
{% endif %}
{% if items.current %}
@ -41,13 +41,13 @@
{% endif %}
{% if items.next %}
{% spaceless %}
{% apply spaceless %}
<li class="pager__item pager__item--mini pager__item--action pager__item--next">
<a{{ items.next.attributes.addClass(pager_action_classes).setAttribute('title', 'Go to next page'|t).setAttribute('href', items.next.href) }}>
<span class="visually-hidden">{{ 'Next page'|t }}</span>
</a>
</li>
{% endspaceless %}
{% endapply %}
{% endif %}
</ul>
</nav>

View File

@ -52,7 +52,7 @@
depth this forum resides at. This will allow us to use CSS
left-margin for indenting.
#}
{% for i in 1..forum.depth if forum.depth > 0 %}<div class="indented">{% endfor %}
{% if forum.depth > 0 %}{% for i in 1..forum.depth %}<div class="indented">{% endfor %}{% endif %}
<div class="forum__icon forum-status-{{ forum.icon_class }}" title="{{ forum.icon_title }}">
<span class="visually-hidden">{{ forum.icon_title }}</span>
</div>
@ -60,7 +60,7 @@
{% if forum.description.value %}
<div class="forum__description">{{ forum.description.value }}</div>
{% endif %}
{% for i in 1..forum.depth if forum.depth > 0 %}</div>{% endfor %}
{% if forum.depth > 0 %}{% for i in 1..forum.depth %}</div>{% endfor %}{% endif %}
</td>
{% if forum.is_container == false %}
<td class="forum__topics">

View File

@ -12,11 +12,11 @@
* @see template_preprocess_link_formatter_link_separate()
*/
#}
{% spaceless %}
{% apply spaceless %}
<div class="link-item">
{% if title %}
<div class="link-title">{{ title }}</div>
{% endif %}
<div class="link-url">{{ link }}</div>
</div>
{% endspaceless %}
{% endapply %}

View File

@ -10,11 +10,11 @@
*/
#}
{% if children %}
{% spaceless %}
{% apply spaceless %}
<div class="dropbutton-wrapper">
<div class="dropbutton-widget">
{{ children }}
</div>
</div>
{% endspaceless %}
{% endapply %}
{% endif %}

View File

@ -10,7 +10,7 @@
* @see template_preprocess_select()
*/
#}
{% spaceless %}
{% apply spaceless %}
<select{{ attributes }}>
{% for option in options %}
{% if option.type == 'optgroup' %}
@ -24,4 +24,4 @@
{% endif %}
{% endfor %}
</select>
{% endspaceless %}
{% endapply %}

View File

@ -34,12 +34,12 @@
to be exported as printer-friendly HTML.
#}
{% for i in 1..depth-1 if depth > 1 %}
{% if depth > 1 %}{% for i in 1..depth-1 %}
<div class="section-{{ i }}">
{% endfor %}
{% endfor %}{% endif %}
{{ contents }}
{% for i in 1..depth-1 if depth > 1 %}
{% if depth > 1 %}{% for i in 1..depth-1 %}
</div>
{% endfor %}
{% endfor %}{% endif %}
</body>
</html>

View File

@ -27,7 +27,7 @@
{% set tray = trays[key] %}
<div{{ tab.attributes.addClass('toolbar-tab') }}>
{{ tab.link }}
{% spaceless %}
{% apply spaceless %}
<div{{ tray.attributes }}>
{% if tray.label %}
<nav class="toolbar-lining clearfix" role="navigation" aria-label="{{ tray.label }}">
@ -38,7 +38,7 @@
{{ tray.links }}
</nav>
</div>
{% endspaceless %}
{% endapply %}
</div>
{% endfor %}
</nav>

View File

@ -8,6 +8,7 @@
use Drupal\Component\Utility\Html;
use Drupal\Core\Render\Markup;
use Drupal\Core\Extension\Extension;
use Twig\Error\RuntimeError;
/**
* Implements hook_theme().
@ -52,7 +53,7 @@ function twig_init(Extension $theme) {
* The output generated by the template, plus any debug information.
*/
function twig_render_template($template_file, array $variables) {
/** @var \Twig_Environment $twig_service */
/** @var \Twig\Environment $twig_service */
$twig_service = \Drupal::service('twig');
$output = [
'debug_prefix' => '',
@ -63,10 +64,10 @@ function twig_render_template($template_file, array $variables) {
try {
$output['rendered_markup'] = $twig_service->loadTemplate($template_file)->render($variables);
}
catch (\Twig_Error_Runtime $e) {
catch (RuntimeError $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.
// \Twig\Template::displayWithErrorHandling()'s exception.
$previous_exception = $e->getPrevious();
if ($previous_exception) {
throw $previous_exception;

View File

@ -12,11 +12,11 @@
* @see template_preprocess_block_content_add_list()
*/
#}
{% spaceless %}
{% apply spaceless %}
<dl>
{% for type in types %}
<dt>{{ type.link }}</dt>
<dd>{{ type.description }}</dd>
{% endfor %}
</dl>
{% endspaceless %}
{% endapply %}

View File

@ -11,7 +11,7 @@
* @see template_preprocess_ckeditor_settings_toolbar()
*/
#}
{% spaceless %}
{% apply spaceless %}
<fieldset role="form" aria-labelledby="ckeditor-button-configuration ckeditor-button-description">
<legend id="ckeditor-button-configuration">{{ 'Toolbar configuration'|t }}</legend>
<div class="fieldset-wrapper">
@ -70,4 +70,4 @@
</div>
</div>
</fieldset>
{% endspaceless %}
{% endapply %}

View File

@ -9,4 +9,4 @@
* - size: Optional. The number of indentations to create.
*/
#}
{% for i in 1..size if size > 0 %}<div class="js-indentation indentation">&nbsp;</div>{% endfor %}
{% if size > 0 %}{% for i in 1..size %}<div class="js-indentation indentation">&nbsp;</div>{% endfor %}{% endif %}

View File

@ -48,7 +48,7 @@
depth this forum resides at. This will allow us to use CSS
left-margin for indenting.
#}
{% for i in 1..forum.depth if forum.depth > 0 %}<div class="indent">{% endfor %}
{% if forum.depth > 0 %}{% for i in 1..forum.depth %}<div class="indent">{% endfor %}{% endif %}
<div title="{{ forum.icon_title }}">
<span class="visually-hidden">{{ forum.icon_title }}</span>
</div>
@ -56,7 +56,7 @@
{% if forum.description.value %}
<div>{{ forum.description.value }}</div>
{% endif %}
{% for i in 1..forum.depth if forum.depth > 0 %}</div>{% endfor %}
{% if forum.depth > 0 %}{% for i in 1..forum.depth %}</div>{% endfor %}{% endif %}
</td>
{% if forum.is_container == false %}
<td>

View File

@ -12,7 +12,7 @@
* @see template_preprocess_link_formatter_link_separate()
*/
#}
{% spaceless %}
{% apply spaceless %}
{{ title }}
{{ link }}
{% endspaceless %}
{% endapply %}

View File

@ -10,11 +10,11 @@
*/
#}
{% if children %}
{% spaceless %}
{% apply spaceless %}
<div class="dropbutton-wrapper">
<div class="dropbutton-widget">
{{ children }}
</div>
</div>
{% endspaceless %}
{% endapply %}
{% endif %}

View File

@ -10,7 +10,7 @@
* @see template_preprocess_select()
*/
#}
{% spaceless %}
{% apply spaceless %}
<select{{ attributes }}>
{% for option in options %}
{% if option.type == 'optgroup' %}
@ -24,4 +24,4 @@
{% endif %}
{% endfor %}
</select>
{% endspaceless %}
{% endapply %}

View File

@ -34,12 +34,12 @@
to be exported as printer-friendly HTML.
#}
{% for i in 1..depth-1 if depth > 1 %}
{% if depth > 1 %}{% for i in 1..depth-1 %}
<div>
{% endfor %}
{% endfor %}{% endif %}
{{ contents }}
{% for i in 1..depth-1 if depth > 1 %}
{% if depth > 1 %}{% for i in 1..depth-1 %}
</div>
{% endfor %}
{% endfor %}{% endif %}
</body>
</html>

View File

@ -27,7 +27,7 @@
{% set tray = trays[key] %}
<div{{ tab.attributes.addClass('toolbar-tab') }}>
{{ tab.link }}
{% spaceless %}
{% apply spaceless %}
<div{{ tray.attributes }}>
{% if tray.label %}
<nav class="toolbar-lining clearfix" role="navigation" aria-label="{{ tray.label }}">
@ -38,7 +38,7 @@
{{ tray.links }}
</nav>
</div>
{% endspaceless %}
{% endapply %}
</div>
{% endfor %}
</nav>