Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
Joining strings and preserving safeness id extremely painful in Drupal. We need a way to do this sanely with minor changes to the current API and preserving performance.
Proposed resolution
Support arrays of strings in #markup and filter or escape according to using #safe_strategy and #allowed_tags.
$render_array = [
'#markup => [
t('Lorem'),
', '
t('ipsum').
],
];
print $renderer->render($render_array); // prints "Lorem, ipsum."
All non-safe strings (t()
's output is safe) are by default admin filtered. Safe strings are considered safe and left unfiltered or escaped. This behaviour can be changed by using #safe_strategy
and #allowed_tags
.
Remaining tasks
Agree this is worthwhile.
Review
Commit
User interface changes
None.
API changes
No change only addition.
Data model changes
None.
Comment | File | Size | Author |
---|---|---|---|
#22 | alex_render_perf_test3.txt | 1.52 KB | alexpott |
#21 | 2554073.20.patch | 5.07 KB | alexpott |
#21 | 12-20-interdiff.txt | 3.17 KB | alexpott |
#18 | render_perf_test_other_twig.txt | 1.47 KB | stefan.r |
#14 | render_perf_test.php_.txt | 1.45 KB | stefan.r |
Comments
Comment #2
alexpottComment #3
alexpottSo for example the code in #2296929: Remove system_requirements() SafeMarkup::set() use could become...
Comment #4
alexpottComment #5
alexpottComment #6
xjmFWIW I think this is a good idea.
Comment #7
xjmA note regarding the beta eligibility of this: This is a followup to a critical (the whole
SafeMarkup::set()
removal meta) and therefore I think it can be accepted during the beta provided the impact outweighs the disruption if we decide to go forward with it.Comment #8
xjmAlso relevant (in addition to the related issues): the
HelpController
. And some others I haven't tracked down yet.Comment #9
xjmComment #10
xjmComment #11
catchThe example in #3 looks like it should be a single t() string to me. In some languages, you might have 'cron' in the first sentence, but then no pronouns at all in later sentences because the context has already been set (i.e. "To run manually from outside the site.." - no 'cron', no 'it'). Each sentence as a t() string prevents a translator from doing that if they wanted to. Whether they want to probably depends on the language.
xjm and alexpott pointed out two things in irc:
1. We already do this in 7.x - this is true, but doesn't mean it's necessarily correct.
2. Conditional strings make it tricky - three short strings where one is conditional vs. two long strings that are identical except for the conditional.
Concern for me is that t() . t() . t() is a workaround, and render arrays of #markup is a workaround, but this would provide a proper way to do this, whereas we might just want to encourage longer t() strings for these cases.
Comment #12
alexpottWe can also use this to support separators... in a way more efficient manor.
With the patch attached and the patch in #2505931: Remove SafeMarkup::set in ViewListBuilder and using the script https://gist.github.com/alexpott/8b3d9b3a55e87919ec20 with opcache enabled and through a browser.
Comment #13
alexpottAlso perhaps I didn't give the best example by using
t()
since this has become a debate about what is best for translators. The result oft()
is just one thing that we're adding together and we need to remain safe:SafeMarkup::format('@onefish @twofish')
eg.Comment #14
stefan.r CreditAttribution: stefan.r commented@alexpott I'm not sure about that benchmark, can you try attached?
Comment #15
alexpott@stefan.r
You are priming the inline list - this is not right.
Comment #16
alexpottBut also... we should use the same escaping strategy!... nice spot @stefan.r
With the performance script attached:
Comment #17
alexpottComment #18
stefan.r CreditAttribution: stefan.r commentedWell I like the idea of being able to do
['#separator' => ', ', '#markup' => $arr]
, that was just to see how much faster the patch in this issue was faster in such case. If we just prime an empty markup array we initialize the theme during the benchmark so that's not exactly right either.What if we prime another twig template which should be a more realistic comparison? (see attached)
Comment #19
alexpott@stefan.r you still need to set the #safe_strategy in the markup array... when you do that and prime with another twig template you get:
But #markup is going to be primed 99.9999999% of the time.
If you prime both another twig template and #markup...
Comment #20
stefan.r CreditAttribution: stefan.r commentedAbout the safe_strategy, yes -- I hadn't seen your posts in #16/#17 yet.
Assuming that latest benchmark is the most realistic of all a 2ms improvement is significant...
Comment #21
alexpottHere's a way that we can optimise the escaping/filtering and only do it once... which means that the importance of setting the escaping strategy disappears.
Results with the perf script attached:
Comment #22
alexpottComment #23
Wim Leers+1
#19: So, Twig render array 2–3 milliseconds, #markup render array 0.6–0.7 milliseconds. Quite big difference.
#21: and here 3.5 ms vs 1.1. Why did #markup render array get roughly twice as slow in this new iteration?
Comment #24
catchI posted on #2505931: Remove SafeMarkup::set in ViewListBuilder - what Views is doing currently also feels wrong to me.
I'd be tempted to say we should use the 'array of render arrays with markup' workaround for these cases, that's not a functional regression from HEAD since we're already handling those strings wrong for RTL in those cases.
That leaves us with some ugly code, but sometimes ugly code for doing ugly things is what you want. Then we can look at a nice inline option for item lists and/or making concatenated t() strings into longer single strings (or find out my RTL concern is misplaced and do this patch) in a minor release.
Comment #25
stefan.r CreditAttribution: stefan.r commentedDo we need to revive this?
Comment #28
lauriiiComment #29
anish.a CreditAttribution: anish.a at Axelerant commentedThe
core/lib/Drupal/Core/Render/Element/Markup.php
file is removed on the following commitThis is not a trivial reroll. May have to rewrite the patch.
Comment #31
arunkumarkThe file does not appear further, So ned to re-write so removing tag
Needs rerolland adding rewrite