Problem/Motivation

In template_preprocess_html() we call out to Safemarkup::format() 4 times on every request.
This function itself is not slow, but why do we use it, when we know that $type is a basic string and $token is fine as well.

Proposed resolution

Use Safestring

Remaining tasks

Discuss whether its worth to microopt. this.

User interface changes

API changes

Data model changes

Comments

dawehner’s picture

Status: Active » Needs review
StatusFileSize
new1.95 KB
Function Name Calls Diff Calls
Diff%
Incl. Wall
Diff
(microsec)
IWall
Diff%
Incl.
MemUse
Diff
(bytes)
IMemUse
Diff%
Incl.
PeakMemUse
Diff
(bytes)
IPeakMemUse
Diff%
Current Function
template_preprocess_html 0 N/A% 146 12.4% -8,784 -259.6% -16,736 -523.0%
Exclusive Metrics Diff for Current Function 147 100.7% 1,440 16.4% 0 0.0%
Parent function
Drupal\Core\Theme\ThemeManager::render 0 N/A% 146 100.0% -8,784 -100.0% -16,736 -100.0%
Child functions
Drupal\Component\Utility\SafeMarkup::format -4 N/A% -92 -63.0% -10,912 -124.2% -16,752 -100.1%
Drupal\Component\Utility\Crypt::randomBytesBase64 0 N/A% 58 39.7% 0 0.0% 0 0.0%
Drupal::config 0 N/A% 11 7.5% 0 0.0% 0 0.0%
strip_tags 0 N/A% 11 7.5% 0 0.0% 0 0.0%
Drupal\Core\Template\Attribute::offsetSet 0 N/A% 5 3.4% 24 0.3% 0 0.0%
spl_autoload_call 0 N/A% 4 2.7% 0 0.0% -8 -0.0%
Drupal\Core\Language\LanguageManager::getCurrentLanguage 0 N/A% 1 0.7% 0 0.0% 0 0.0%
Drupal\Core\Render\SafeString::__construct 4 N/A% 1 0.7% 664 7.6% 0 0.0%
Drupal\Core\Config\Config::get 0 N/A% 0 0.0% 0 0.0% 24 0.1%
trim 0 N/A% 0 0.0% 0 0.0% 0 0.0%
Drupal::service 0 N/A% 0 0.0% 0 0.0% 0 0.0%
Drupal\Core\Template\Attribute::__construct 0 N/A% 0 0.0% 0 0.0% 0 0.0%
Drupal::languageManager 0 N/A% 0 0.0% 0 0.0% 0 0.0%
Drupal\Core\Language\Language::getId 0 N/A% 0 0.0% 0 0.0% 0 0.0%
Drupal\Core\Language\Language::getDirection 0 N/A% 0 0.0% 0 0.0% 0 0.0%
Drupal\Core\Path\PathMatcher::isFrontPage 0 N/A% 0 0.0% 0 0.0% 0 0.0%
fabianx’s picture

What is wrong to use SafeString::create() - more effort?

Otherwise +1, SafeString did not exist at that time of writing this.

dawehner’s picture

What is wrong to use SafeString::create() - more effort?

Well, I think its just odd as an API when you know the string already being a string.

fabianx’s picture

Status: Needs review » Reviewed & tested by the community

Okay, agree.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Core/Render/SafeString.php
@@ -36,6 +36,19 @@ class SafeString implements SafeStringInterface, \Countable {
   /**
+   * Constructs a new SafeString instance.
+   *
+   * Better use SafeString::create() as the string might not be an actual
+   * string.
+   *
+   * @param string $string
+   *  (optional) The string.
+   */
+  public function __construct($string = '') {
+    $this->string = $string;
+  }

I'm not yay about adding a constructor but at the very least we should enforce when it should be used. An exception should be thrown if $string is not a string and when it is empty. Also the docs need improving to say when to use the constructor and when to use create.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new1.2 KB
new1.57 KB

Yeah let's be clear, this change was not needed.

stefan.r’s picture

This looks good now.

+++ b/core/includes/theme.inc
@@ -1290,10 +1291,9 @@ function template_preprocess_html(&$variables) {
+    // We can construct a SafeString as we know that both $type and $token is

Nit: are

stefan.r’s picture

Status: Needs review » Reviewed & tested by the community

Let's have @alexpott have another look at this

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 6: 2538950-6.patch, failed testing.

stefan.r’s picture

Status: Needs work » Reviewed & tested by the community
StatusFileSize
new1.21 KB

reroll

alexpott’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new2.46 KB

I think a completely different and maybe more honest approach is available. Let's just print the raw variables in the twig template and attach everything to the html render. 4 less calls to SafeMarkup::format and 4 less calls to render.

stefan.r’s picture

Are we sure the data we receive in the template comes from template_preprocess_html(), will this still be OK if a theme has its own preprocess implementation?

alexpott’s picture

StatusFileSize
new3.08 KB
new3.4 KB

We can even do this which makes it way more obvious what is going on in the template.

stefan.r’s picture

That seems clearer, so realistically themes would never touch that anyway

alexpott’s picture

StatusFileSize
new2.72 KB
new5.64 KB

Fixing the template docs. I still think we should print the raw token - if a developer changes the token and adds raw html imo that is just silly and we shouldn't use auto-escape to prevent that. What auto-escape should be for is ensuring user generated input is escaped when printed in templates.

wim leers’s picture

Wow, this sure is a very interesting approach!

I have a few concerns about going in this direction:

  1. it makes the template look super scary
  2. it makes it impossible to add other things to those variables.

Yet both of these concerns are arguably good things: both help ensure themers don't accidentally break CSS or JS loading. In that sense, it even clarifies things: because {{ styles }} and {{ scripts }} and {{ scripts_bottom }} make themers think they are printing CSS/JS, but they're not: they're printing placeholders.

But in that case, I'd propose some renaming to make it at least less cryptic:

+++ b/core/modules/system/templates/html.html.twig
@@ -33,10 +28,10 @@
+    <drupal-html-response-attachment-placeholder type="head" token="{{ token|raw }}"></drupal-html-response-attachment-placeholder>
...
+    <drupal-html-response-attachment-placeholder type="styles" token="{{ token|raw }}"></drupal-html-response-attachment-placeholder>
+    <drupal-html-response-attachment-placeholder type="scripts" token="{{ token|raw }}"></drupal-html-response-attachment-placeholder>

@@ -45,6 +40,6 @@
+    <drupal-html-response-attachment-placeholder type="scripts_bottom" token="{{ token|raw }}"></drupal-html-response-attachment-placeholder>

<css-attachments-placeholder token="{{ attachments_token|raw }}">

So: "head", "css", "js" and "js-bottom" is what I would propose.

And renaming the "token" variable to "attachments_token".

alexpott’s picture

StatusFileSize
new4.58 KB
new5.31 KB

After discussing with @Wim Leers a bit more on IRC we went for the following approach...

wim leers’s picture

Issue tags: +Needs change record

Looks good! Let's see what testbot says.

One important remark: every D8 theme that has its own html.html.twig template will need to be updated.

star-szr’s picture

Fancy! No objections from me. Just want to confirm this docs removal is because something is being removed (or is just out of date/wrong/etc.):

+++ b/core/modules/system/templates/html.html.twig
@@ -7,9 +7,6 @@
- * - css: A list of CSS files for the current page.
wim leers’s picture

Status: Needs review » Reviewed & tested by the community

Great! With front-end/themer sign-off, I think this is RTBC.

#20: That css variable is indeed out of date/wrong: $variables['css'] is not being set anywhere.

alexpott’s picture

Title: Use Safestring instead of SafeMarkup::format() in template_preprocess_html » Replace SafeMarkup::format() in template_preprocess_html with placeholders in the template
catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed to 8.0.x, thanks!

  • catch committed 6b46410 on 8.0.x
    Issue #2538950 by alexpott, dawehner, stefan.r: Replace SafeMarkup::...
catch’s picture

Priority: Normal » Major

Posthumous priority change.

alexpott’s picture

wim leers’s picture

  • alexpott committed 36f6a9b on 8.0.x
    Issue #2565033 by Wim Leers: Follow-up for #2538950: simplify syntax
    

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

Jeff Burnz’s picture

Initially this worked in my theme, however after a recent update (no idea which one) all I get now is this:

<head-placeholder token="GyB5DIbKTxnBAR1qiGzevTSOCsi4EQ9dLK3mMCYAANc6HDRx1EA4MMiqsw7Y9_f7KKFOo8Xa5A" />

...so no styles, js etc is output, only what you see above. Anyone have an insight into why this might be?

Ok, so this is patently obvious now I have looked at this again - for some reason I have treated these like self closing html tags and used a forward slash, this caused them to fail - they should look like this:

<head-placeholder token="{{ placeholder_token|raw }}">

Not...

<head-placeholder token="{{ placeholder_token|raw }}" />

edit - I updated this in case any one else made the same silly mistake. Apologies for the noise.

joelpittet’s picture

+++ b/core/modules/system/templates/html.html.twig
@@ -33,10 +28,10 @@
+    <head-placeholder token="{{ placeholder_token|raw }}" />
...
+    <css-placeholder token="{{ placeholder_token|raw }}" />
+    <js-placeholder token="{{ placeholder_token|raw }}" />

@@ -45,6 +40,6 @@
+    <js-bottom-placeholder token="{{ placeholder_token|raw }}" />

+++ b/core/themes/classy/templates/layout/html.html.twig
@@ -39,10 +34,10 @@
+    <head-placeholder token="{{ placeholder_token|raw }}" />
...
+    <css-placeholder token="{{ placeholder_token|raw }}" />
+    <js-placeholder token="{{ placeholder_token|raw }}" />

@@ -51,6 +46,6 @@
+    <js-bottom-placeholder token="{{ placeholder_token|raw }}" />

We try to avoid |raw to discourage it's use. Unfortunately this got in to RC release. Any chance we can wrap this placeholder in a Markup/SafeString type object?

I just noticed this when trying to get basic theme upgraded to D8

joelpittet’s picture

Made a follow-up to get those out. #2603074: Remove |raw from use in core templates