Rendering & Autoescape
Lauri Eskola
Caching in Drupal 8
Different types of caching
From fastest to slower:
- Internal page cache
- Dynamic page cache
- Render cache
"I'm rendering something. That means I must think of cacheability."
Cacheable metadata
Cache contexts
"Cache contexts provide a declarative way to create context-dependent variations of something that needs to be cached."
Example
Some expensive-to-calculate data depends on the active theme: different results for different themes. Then you'd vary by the theme cache context.
Cache tags
"Cache tags provide a declarative way to track which cache items depend on some data managed by Drupal."
Example
'node:5' - cache tag for Node entity 5 (invalidated whenever it changes)
Cache max-age
"Cache max-age provides a declarative way to create time-dependent caches. "
Example
A cache max -age is a positive integer, expressing a number of seconds.
How to declare cacheable metadata
$build = [
'#prefix' => '',
'#markup' => t('Hi, %name, welcome back to @site!', [
'%name' => $current_user->getUsername(),
'@site' => $config->get('name'),
]),
'#suffix' => '',
'#cache' => [
'contexts' => [
// The "current user" is used above, which depends on the request,
// so we tell Drupal to vary by the 'user' cache context.
'user',
],
],
];
Making something cacheable manually
cache keys: when rendering a node (thing) in the teaser view mode (configuration indicating a specific representation), my cache keys would be e.g. [ 'node' , 5 , 'teaser' ]
Markup should live inside a Twig template. Not in PHP!
Rule #1
Autoescape
What is escaping?
<?php
use Drupal\Component\Utility\Html
print Html::escape('<em>Kittens</em>');
Prints markup in HTML
<em>Kittens</em>
<em>Kittens</em>
Prints in the browser
What is Autoescaping?
{{ text }}
Prints markup in HTML
<em>Kittens</em>
<em>Kittens</em>
<?php
function bartik_preprocess_page(&$variables) {
$variables['text'] = '<em>Kittens</em>';
}
Prints in the browser
Why do we need autoescaping?
Why do we need autoescaping?
How to avoid autoescaping?
{{ text }}
Prints markup in HTML
<em>Kittens</em>
Kittens
<?php
function bartik_preprocess_page(&$variables) {
$variables['text']['#markup'] = '<em>Kittens</em>';
}
Prints in the browser
How to avoid autoescaping?
{{ text }}
Prints markup in HTML
<em>Kittens</em>
Kittens
<?php
use Drupal\Component\Render\FormattableMarkup;
function bartik_preprocess_page(&$variables) {
$variables['text'] = new FormattableMarkup('<em>@txt</em>', ['@txt' => 'Kittens']);
}
Prints in the browser
But it has also its caveats...
When autoescaped strings are safe?
Whenever the escaped string is being printed in HTML node.
Attributes are NOT HTML!
<?php
use Drupal\Component\Render\FormattableMarkup;
new FormattableMarkup('<em@txt></em>', ['@txt' => 'Kittens']);
new FormattableMarkup('<a href="@url"></a>', ['@url' => 'http://kittens.com']);
new FormattableMarkup('<a href="@url"></a>', [
'@url' => 'javascript:alert(String.fromCharCode(88,83,83))'
]);
These are all dangerous:
New placeholder for URLs
<?php
use Drupal\Component\Render\FormattableMarkup;
new FormattableMarkup('<a href=":url"></a>', [
':url' => 'javascript:alert(String.fromCharCode(88,83,83))'
]);
This is safe:
Array keys
<?php
use Drupal\Core\StringTranslation\TranslatableMarkup;
// These two do the same thing.
$text = new TranslatableMarkup('Translate me');
$text = t('Translate me');
$array[$text] = $text;
<?php
use Drupal\Core\StringTranslation\TranslatableMarkup;
$text = new TranslatableMarkup('Translate me');
$array[(string) $text] = $text;
This will fatal:
This works:
Autoescaping is only enabled for Twig templates
Which means using any custom templating engine or Theme functions are not autoescaped
That's why PHPTemplate was overtaken by the amazing Nyan Cat templating engine.
https://www.drupal.org/node/2575199
Rendering & Autoescape
By lauriii
Rendering & Autoescape
- 1,721