Commit d3c33d58 authored by catch's avatar catch

Issue #2506581 by alexpott, Wim Leers, Fabianx, xjm, joelpittet, Cottser,...

Issue #2506581 by alexpott, Wim Leers, Fabianx, xjm, joelpittet, Cottser, dawehner: Remove SafeMarkup::set() from Renderer::doRender
parent 8c8bf756
...@@ -563,7 +563,7 @@ function drupal_set_message($message = NULL, $type = 'status', $repeat = FALSE) ...@@ -563,7 +563,7 @@ function drupal_set_message($message = NULL, $type = 'status', $repeat = FALSE)
$new = array( $new = array(
'safe' => SafeMarkup::isSafe($message), 'safe' => SafeMarkup::isSafe($message),
'message' => $message, 'message' => (string) $message,
); );
if ($repeat || !in_array($new, $_SESSION['messages'][$type])) { if ($repeat || !in_array($new, $_SESSION['messages'][$type])) {
$_SESSION['messages'][$type][] = $new; $_SESSION['messages'][$type][] = $new;
......
...@@ -164,15 +164,15 @@ protected function buildAttachmentsCommands(AjaxResponse $response, Request $req ...@@ -164,15 +164,15 @@ protected function buildAttachmentsCommands(AjaxResponse $response, Request $req
$resource_commands = array(); $resource_commands = array();
if ($css_assets) { if ($css_assets) {
$css_render_array = $this->cssCollectionRenderer->render($css_assets); $css_render_array = $this->cssCollectionRenderer->render($css_assets);
$resource_commands[] = new AddCssCommand($this->renderer->renderPlain($css_render_array)); $resource_commands[] = new AddCssCommand((string) $this->renderer->renderPlain($css_render_array));
} }
if ($js_assets_header) { if ($js_assets_header) {
$js_header_render_array = $this->jsCollectionRenderer->render($js_assets_header); $js_header_render_array = $this->jsCollectionRenderer->render($js_assets_header);
$resource_commands[] = new PrependCommand('head', $this->renderer->renderPlain($js_header_render_array)); $resource_commands[] = new PrependCommand('head', (string) $this->renderer->renderPlain($js_header_render_array));
} }
if ($js_assets_footer) { if ($js_assets_footer) {
$js_footer_render_array = $this->jsCollectionRenderer->render($js_assets_footer); $js_footer_render_array = $this->jsCollectionRenderer->render($js_assets_footer);
$resource_commands[] = new AppendCommand('body', $this->renderer->renderPlain($js_footer_render_array)); $resource_commands[] = new AppendCommand('body', (string) $this->renderer->renderPlain($js_footer_render_array));
} }
foreach (array_reverse($resource_commands) as $resource_command) { foreach (array_reverse($resource_commands) as $resource_command) {
$response->addCommand($resource_command, TRUE); $response->addCommand($resource_command, TRUE);
......
...@@ -37,10 +37,10 @@ protected function getRenderedContent() { ...@@ -37,10 +37,10 @@ protected function getRenderedContent() {
if (is_array($this->content)) { if (is_array($this->content)) {
$html = \Drupal::service('renderer')->renderRoot($this->content); $html = \Drupal::service('renderer')->renderRoot($this->content);
$this->attachedAssets = AttachedAssets::createFromRenderArray($this->content); $this->attachedAssets = AttachedAssets::createFromRenderArray($this->content);
return $html; return (string) $html;
} }
else { else {
return $this->content; return (string) $this->content;
} }
} }
......
...@@ -64,7 +64,7 @@ public function renderResponse(array $main_content, Request $request, RouteMatch ...@@ -64,7 +64,7 @@ public function renderResponse(array $main_content, Request $request, RouteMatch
} }
} }
$html = $this->drupalRenderRoot($main_content); $html = (string) $this->drupalRenderRoot($main_content);
$response->setAttachments($main_content['#attached']); $response->setAttachments($main_content['#attached']);
// The selector for the insert command is NULL as the new content will // The selector for the insert command is NULL as the new content will
...@@ -72,7 +72,7 @@ public function renderResponse(array $main_content, Request $request, RouteMatch ...@@ -72,7 +72,7 @@ public function renderResponse(array $main_content, Request $request, RouteMatch
// behavior can be changed with #ajax['method']. // behavior can be changed with #ajax['method'].
$response->addCommand(new InsertCommand(NULL, $html)); $response->addCommand(new InsertCommand(NULL, $html));
$status_messages = array('#type' => 'status_messages'); $status_messages = array('#type' => 'status_messages');
$output = $this->drupalRenderRoot($status_messages); $output = (string) $this->drupalRenderRoot($status_messages);
if (!empty($output)) { if (!empty($output)) {
$response->addCommand(new PrependCommand(NULL, $output)); $response->addCommand(new PrependCommand(NULL, $output));
} }
......
...@@ -77,11 +77,6 @@ public function get(array $elements) { ...@@ -77,11 +77,6 @@ public function get(array $elements) {
if (isset($cached_element['#cache_redirect'])) { if (isset($cached_element['#cache_redirect'])) {
return $this->get($cached_element); return $this->get($cached_element);
} }
// Ensure that any safe properties are marked safe.
foreach ($cached_element['#safe_cache_properties'] as $cache_property) {
SafeMarkup::set($cached_element[$cache_property]);
}
unset($cached_element['#safe_cache_properties']);
// Return the cached element. // Return the cached element.
return $cached_element; return $cached_element;
} }
...@@ -333,7 +328,6 @@ public function getCacheableRenderArray(array $elements) { ...@@ -333,7 +328,6 @@ public function getCacheableRenderArray(array $elements) {
'tags' => $elements['#cache']['tags'], 'tags' => $elements['#cache']['tags'],
'max-age' => $elements['#cache']['max-age'], 'max-age' => $elements['#cache']['max-age'],
], ],
'#safe_cache_properties' => []
]; ];
// Preserve cacheable items if specified. If we are preserving any cacheable // Preserve cacheable items if specified. If we are preserving any cacheable
...@@ -342,10 +336,10 @@ public function getCacheableRenderArray(array $elements) { ...@@ -342,10 +336,10 @@ public function getCacheableRenderArray(array $elements) {
// the cache entry size. // the cache entry size.
if (!empty($elements['#cache_properties']) && is_array($elements['#cache_properties'])) { if (!empty($elements['#cache_properties']) && is_array($elements['#cache_properties'])) {
$data['#cache_properties'] = $elements['#cache_properties']; $data['#cache_properties'] = $elements['#cache_properties'];
// Store whether any of the cache properties are safe strings. // Ensure that any safe strings are a SafeString object.
foreach (Element::properties(array_flip($elements['#cache_properties'])) as $cache_property) { foreach (Element::properties(array_flip($elements['#cache_properties'])) as $cache_property) {
if (isset($elements[$cache_property]) && !is_array($elements[$cache_property]) && SafeMarkup::isSafe($elements[$cache_property])) { if (isset($elements[$cache_property]) && is_scalar($elements[$cache_property]) && SafeMarkup::isSafe($elements[$cache_property])) {
$data['#safe_cache_properties'][] = $cache_property; $elements[$cache_property] = SafeString::create($elements[$cache_property]);
} }
} }
...@@ -357,12 +351,14 @@ public function getCacheableRenderArray(array $elements) { ...@@ -357,12 +351,14 @@ public function getCacheableRenderArray(array $elements) {
$data['#markup'] = ''; $data['#markup'] = '';
// Cache only cacheable children's markup. // Cache only cacheable children's markup.
foreach ($cacheable_children as $key) { foreach ($cacheable_children as $key) {
$cacheable_items[$key] = ['#markup' => $cacheable_items[$key]['#markup']]; // We can assume that #markup is safe at this point.
$cacheable_items[$key] = ['#markup' => SafeString::create($cacheable_items[$key]['#markup'])];
} }
} }
$data += $cacheable_items; $data += $cacheable_items;
} }
$data['#markup'] = SafeString::create($data['#markup']);
return $data; return $data;
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
use Drupal\Component\Utility\SafeMarkup; use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\UrlHelper; use Drupal\Component\Utility\UrlHelper;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Access\AccessResultInterface; use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Cache\CacheableMetadata;
...@@ -277,15 +278,9 @@ protected function doRender(&$elements, $is_root_call = FALSE) { ...@@ -277,15 +278,9 @@ protected function doRender(&$elements, $is_root_call = FALSE) {
if ($is_root_call) { if ($is_root_call) {
$this->replacePlaceholders($elements); $this->replacePlaceholders($elements);
} }
// Mark the element markup as safe. If we have cached children, we need // Mark the element markup as safe if is it a string.
// to mark them as safe too. The parent markup contains the child if (is_string($elements['#markup'])) {
// markup, so if the parent markup is safe, then the markup of the $elements['#markup'] = SafeString::create($elements['#markup']);
// individual children must be safe as well.
$elements['#markup'] = SafeMarkup::set($elements['#markup']);
if (!empty($elements['#cache_properties'])) {
foreach (Element::children($cached_element) as $key) {
SafeMarkup::set($cached_element[$key]['#markup']);
}
} }
// The render cache item contains all the bubbleable rendering metadata // The render cache item contains all the bubbleable rendering metadata
// for the subtree. // for the subtree.
...@@ -410,7 +405,7 @@ protected function doRender(&$elements, $is_root_call = FALSE) { ...@@ -410,7 +405,7 @@ protected function doRender(&$elements, $is_root_call = FALSE) {
$elements['#children'] = ''; $elements['#children'] = '';
} }
if (isset($elements['#markup'])) { if (!empty($elements['#markup'])) {
// @todo Decide how to support non-HTML in the render API in // @todo Decide how to support non-HTML in the render API in
// https://www.drupal.org/node/2501313. // https://www.drupal.org/node/2501313.
$elements['#markup'] = $this->xssFilterAdminIfUnsafe($elements['#markup']); $elements['#markup'] = $this->xssFilterAdminIfUnsafe($elements['#markup']);
...@@ -452,7 +447,7 @@ protected function doRender(&$elements, $is_root_call = FALSE) { ...@@ -452,7 +447,7 @@ protected function doRender(&$elements, $is_root_call = FALSE) {
foreach ($children as $key) { foreach ($children as $key) {
$elements['#children'] .= $this->doRender($elements[$key]); $elements['#children'] .= $this->doRender($elements[$key]);
} }
$elements['#children'] = SafeMarkup::set($elements['#children']); $elements['#children'] = SafeString::create($elements['#children']);
} }
// If #theme is not implemented and the element has raw #markup as a // If #theme is not implemented and the element has raw #markup as a
...@@ -463,7 +458,7 @@ protected function doRender(&$elements, $is_root_call = FALSE) { ...@@ -463,7 +458,7 @@ protected function doRender(&$elements, $is_root_call = FALSE) {
// required. Eventually #theme_wrappers will expect both #markup and // required. Eventually #theme_wrappers will expect both #markup and
// #children to be a single string as #children. // #children to be a single string as #children.
if (!$theme_is_implemented && isset($elements['#markup'])) { if (!$theme_is_implemented && isset($elements['#markup'])) {
$elements['#children'] = SafeMarkup::set($elements['#markup'] . $elements['#children']); $elements['#children'] = SafeString::create($elements['#markup'] . $elements['#children']);
} }
// Let the theme functions in #theme_wrappers add markup around the rendered // Let the theme functions in #theme_wrappers add markup around the rendered
...@@ -551,8 +546,7 @@ protected function doRender(&$elements, $is_root_call = FALSE) { ...@@ -551,8 +546,7 @@ protected function doRender(&$elements, $is_root_call = FALSE) {
$context->bubble(); $context->bubble();
$elements['#printed'] = TRUE; $elements['#printed'] = TRUE;
$elements['#markup'] = SafeMarkup::set($elements['#markup']); return SafeString::create($elements['#markup']);
return $elements['#markup'];
} }
/** /**
...@@ -710,17 +704,18 @@ public function addCacheableDependency(array &$elements, $dependency) { ...@@ -710,17 +704,18 @@ public function addCacheableDependency(array &$elements, $dependency) {
* Note: This method only filters if $string is not marked safe already. This * Note: This method only filters if $string is not marked safe already. This
* ensures that HTML intended for display is not filtered. * ensures that HTML intended for display is not filtered.
* *
* @param string $string * @param string|\Drupal\Core\Render\SafeString $string
* A string. * A string.
* *
* @return string * @return \Drupal\Core\Render\SafeString
* The escaped string. If SafeMarkup::isSafe($string) returns TRUE, it won't * The escaped string wrapped in a SafeString object. If
* be escaped again. * SafeMarkup::isSafe($string) returns TRUE, it won't be escaped again.
*/ */
protected function xssFilterAdminIfUnsafe($string) { protected function xssFilterAdminIfUnsafe($string) {
// @todo https://www.drupal.org/node/2506581 replace with if (!SafeMarkup::isSafe($string)) {
// SafeMarkup::isSafe() and Xss::filterAdmin(). $string = Xss::filterAdmin($string);
return SafeMarkup::checkAdminXss($string); }
return SafeString::create($string);
} }
} }
...@@ -27,7 +27,7 @@ interface RendererInterface { ...@@ -27,7 +27,7 @@ interface RendererInterface {
* @param array $elements * @param array $elements
* The structured array describing the data to be rendered. * The structured array describing the data to be rendered.
* *
* @return string * @return \Drupal\Component\Utility\SafeStringInterface
* The rendered HTML. * The rendered HTML.
* *
* @see ::render() * @see ::render()
...@@ -58,7 +58,7 @@ public function renderRoot(&$elements); ...@@ -58,7 +58,7 @@ public function renderRoot(&$elements);
* @param array $elements * @param array $elements
* The structured array describing the data to be rendered. * The structured array describing the data to be rendered.
* *
* @return string * @return \Drupal\Component\Utility\SafeStringInterface
* The rendered HTML. * The rendered HTML.
* *
* @see ::renderRoot() * @see ::renderRoot()
...@@ -302,7 +302,7 @@ public function renderPlain(&$elements); ...@@ -302,7 +302,7 @@ public function renderPlain(&$elements);
* (Internal use only.) Whether this is a recursive call or not. See * (Internal use only.) Whether this is a recursive call or not. See
* ::renderRoot(). * ::renderRoot().
* *
* @return string * @return \Drupal\Component\Utility\SafeStringInterface
* The rendered HTML. * The rendered HTML.
* *
* @throws \LogicException * @throws \LogicException
......
<?php
/**
* @file
* Contains \Drupal\Core\Render\SafeString.
*/
namespace Drupal\Core\Render;
use Drupal\Component\Utility\SafeStringInterface;
use Drupal\Component\Utility\Unicode;
/**
* Defines an object that passes safe strings through the render system.
*
* This object should only be constructed with a known safe string. If there is
* any risk that the string contains user-entered data that has not been
* filtered first, it must not be used.
*
* @internal
* This object is marked as internal because it should only be used during
* rendering. Currently, there is no use case for this object by contrib or
* custom code.
*
* @see \Drupal\Core\Template\TwigExtension::escapeFilter
* @see \Twig_Markup
* @see \Drupal\Component\Utility\SafeMarkup
*/
class SafeString implements SafeStringInterface, \Countable {
/**
* The safe string.
*
* @var string
*/
protected $string;
/**
* Creates a SafeString object if necessary.
*
* If $string is equal to a blank string then it is not necessary to create a
* SafeString object. If $string is an object that implements
* SafeStringInterface it is returned unchanged.
*
* @param mixed $string
* The string to mark as safe. This value will be cast to a string.
*
* @return string|\Drupal\Component\Utility\SafeStringInterface
* A safe string.
*/
public static function create($string) {
if ($string instanceof SafeStringInterface) {
return $string;
}
$string = (string) $string;
if ($string === '') {
return '';
}
$safe_string = new static();
$safe_string->string = $string;
return $safe_string;
}
/**
* Returns the string version of the SafeString object.
*
* @return string
* The safe string content.
*/
public function __toString() {
return $this->string;
}
/**
* Returns the string length.
*
* @return int
* The length of the string.
*/
public function count() {
return Unicode::strlen($this->string);
}
}
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
namespace Drupal\Core\StringTranslation; namespace Drupal\Core\StringTranslation;
use Drupal\Component\Utility\SafeStringInterface;
/** /**
* Provides a class to wrap a translatable string. * Provides a class to wrap a translatable string.
* *
...@@ -16,7 +18,7 @@ ...@@ -16,7 +18,7 @@
* *
* @see \Drupal\Core\Annotation\Translation * @see \Drupal\Core\Annotation\Translation
*/ */
class TranslationWrapper { class TranslationWrapper implements SafeStringInterface {
use StringTranslationTrait; use StringTranslationTrait;
/** /**
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
use Drupal\Component\Utility\SafeMarkup; use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\PhpStorage\PhpStorageFactory; use Drupal\Core\PhpStorage\PhpStorageFactory;
use Drupal\Core\Render\SafeString;
/** /**
* A class that defines a Twig environment for Drupal. * A class that defines a Twig environment for Drupal.
...@@ -194,17 +195,15 @@ public function getTemplateClass($name, $index = NULL) { ...@@ -194,17 +195,15 @@ public function getTemplateClass($name, $index = NULL) {
* @param array $context * @param array $context
* An array of parameters to pass to the template. * An array of parameters to pass to the template.
* *
* @return string * @return \Drupal\Component\Utility\SafeStringInterface|string
* The rendered inline template. * The rendered inline template as a SafeString object.
* *
* @see \Drupal\Core\Template\Loader\StringLoader::exists() * @see \Drupal\Core\Template\Loader\StringLoader::exists()
*/ */
public function renderInline($template_string, array $context = array()) { public function renderInline($template_string, array $context = array()) {
// Prefix all inline templates with a special comment. // Prefix all inline templates with a special comment.
$template_string = '{# inline_template_start #}' . $template_string; $template_string = '{# inline_template_start #}' . $template_string;
// @todo replace with object implementating SafeStringInterface in return SafeString::create($this->loadTemplate($template_string, NULL)->render($context));
// https://www.drupal.org/node/2506581.
return SafeMarkup::set($this->loadTemplate($template_string, NULL)->render($context));
} }
} }
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
use Drupal\Component\Serialization\Json; use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\SafeMarkup; use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\SafeStringInterface;
use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\GeneratedLink; use Drupal\Core\GeneratedLink;
use Drupal\Core\Link; use Drupal\Core\Link;
...@@ -106,6 +107,13 @@ public function generate($text, Url $url, $collect_bubbleable_metadata = FALSE) ...@@ -106,6 +107,13 @@ public function generate($text, Url $url, $collect_bubbleable_metadata = FALSE)
$variables['options']['attributes']['hreflang'] = $variables['options']['language']->getId(); $variables['options']['attributes']['hreflang'] = $variables['options']['language']->getId();
} }
// Ensure that query values are strings.
array_walk($variables['options']['query'], function(&$value) {
if ($value instanceof SafeStringInterface) {
$value = (string) $value;
}
});
// Set the "active" class if the 'set_active_class' option is not empty. // Set the "active" class if the 'set_active_class' option is not empty.
if (!empty($variables['options']['set_active_class']) && !$url->isExternal()) { if (!empty($variables['options']['set_active_class']) && !$url->isExternal()) {
// Add a "data-drupal-link-query" attribute to let the // Add a "data-drupal-link-query" attribute to let the
......
...@@ -190,14 +190,14 @@ protected function verifyRenderCacheHandling() { ...@@ -190,14 +190,14 @@ protected function verifyRenderCacheHandling() {
public function testBlockViewBuilderAlter() { public function testBlockViewBuilderAlter() {
// Establish baseline. // Establish baseline.
$build = $this->getBlockRenderArray(); $build = $this->getBlockRenderArray();
$this->assertIdentical($this->renderer->renderRoot($build), 'Llamas &gt; unicorns!'); $this->assertIdentical((string) $this->renderer->renderRoot($build), 'Llamas &gt; unicorns!');
// Enable the block view alter hook that adds a suffix, for basic testing. // Enable the block view alter hook that adds a suffix, for basic testing.
\Drupal::state()->set('block_test_view_alter_suffix', TRUE); \Drupal::state()->set('block_test_view_alter_suffix', TRUE);
Cache::invalidateTags($this->block->getCacheTagsToInvalidate()); Cache::invalidateTags($this->block->getCacheTagsToInvalidate());
$build = $this->getBlockRenderArray(); $build = $this->getBlockRenderArray();
$this->assertTrue(isset($build['#suffix']) && $build['#suffix'] === '<br>Goodbye!', 'A block with content is altered.'); $this->assertTrue(isset($build['#suffix']) && $build['#suffix'] === '<br>Goodbye!', 'A block with content is altered.');
$this->assertIdentical($this->renderer->renderRoot($build), 'Llamas &gt; unicorns!<br>Goodbye!'); $this->assertIdentical((string) $this->renderer->renderRoot($build), 'Llamas &gt; unicorns!<br>Goodbye!');
\Drupal::state()->set('block_test_view_alter_suffix', FALSE); \Drupal::state()->set('block_test_view_alter_suffix', FALSE);
// Force a request via GET so we can test the render cache. // Force a request via GET so we can test the render cache.
...@@ -218,7 +218,7 @@ public function testBlockViewBuilderAlter() { ...@@ -218,7 +218,7 @@ public function testBlockViewBuilderAlter() {
$expected_keys = array_merge($default_keys, array($alter_add_key)); $expected_keys = array_merge($default_keys, array($alter_add_key));
$build = $this->getBlockRenderArray(); $build = $this->getBlockRenderArray();
$this->assertIdentical($expected_keys, $build['#cache']['keys'], 'An altered cacheable block has the expected cache keys.'); $this->assertIdentical($expected_keys, $build['#cache']['keys'], 'An altered cacheable block has the expected cache keys.');
$this->assertIdentical($this->renderer->renderRoot($build), ''); $this->assertIdentical((string) $this->renderer->renderRoot($build), '');
$cache_entry = $this->container->get('cache.render')->get($cid); $cache_entry = $this->container->get('cache.render')->get($cid);
$this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.'); $this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.');
$expected_tags = array_merge($default_tags, ['rendered']); $expected_tags = array_merge($default_tags, ['rendered']);
...@@ -233,7 +233,7 @@ public function testBlockViewBuilderAlter() { ...@@ -233,7 +233,7 @@ public function testBlockViewBuilderAlter() {
$build = $this->getBlockRenderArray(); $build = $this->getBlockRenderArray();
sort($build['#cache']['tags']); sort($build['#cache']['tags']);
$this->assertIdentical($expected_tags, $build['#cache']['tags'], 'An altered cacheable block has the expected cache tags.'); $this->assertIdentical($expected_tags, $build['#cache']['tags'], 'An altered cacheable block has the expected cache tags.');
$this->assertIdentical($this->renderer->renderRoot($build), ''); $this->assertIdentical((string) $this->renderer->renderRoot($build), '');
$cache_entry = $this->container->get('cache.render')->get($cid); $cache_entry = $this->container->get('cache.render')->get($cid);
$this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.'); $this->assertTrue($cache_entry, 'The block render element has been cached with the expected cache ID.');
$expected_tags = array_merge($default_tags, [$alter_add_tag, 'rendered']); $expected_tags = array_merge($default_tags, [$alter_add_tag, 'rendered']);
...@@ -246,7 +246,7 @@ public function testBlockViewBuilderAlter() { ...@@ -246,7 +246,7 @@ public function testBlockViewBuilderAlter() {
\Drupal::state()->set('block_test_view_alter_append_pre_render_prefix', TRUE); \Drupal::state()->set('block_test_view_alter_append_pre_render_prefix', TRUE);
$build = $this->getBlockRenderArray(); $build = $this->getBlockRenderArray();
$this->assertFalse(isset($build['#prefix']), 'The appended #pre_render callback has not yet run before rendering.'); $this->assertFalse(isset($build['#prefix']), 'The appended #pre_render callback has not yet run before rendering.');
$this->assertIdentical($this->renderer->renderRoot($build), 'Hiya!<br>'); $this->assertIdentical((string) $this->renderer->renderRoot($build), 'Hiya!<br>');
$this->assertTrue(isset($build['#prefix']) && $build['#prefix'] === 'Hiya!<br>', 'A cached block without content is altered.'); $this->assertTrue(isset($build['#prefix']) && $build['#prefix'] === 'Hiya!<br>', 'A cached block without content is altered.');
// Restore the previous request method. // Restore the previous request method.
......
...@@ -143,7 +143,7 @@ function contact_mail($key, &$message, $params) { ...@@ -143,7 +143,7 @@ function contact_mail($key, &$message, $params) {
$message['subject'] .= t('[!form] !subject', $variables, $options); $message['subject'] .= t('[!form] !subject', $variables, $options);
$message['body'][] = t("!sender-name (!sender-url) sent a message using the contact form at !form-url.", $variables, $options); $message['body'][] = t("!sender-name (!sender-url) sent a message using the contact form at !form-url.", $variables, $options);
$build = entity_view($contact_message, 'mail', $language->getId()); $build = entity_view($contact_message, 'mail', $language->getId());
$message['body'][] = \Drupal::service('renderer')->renderPlain($build); $message['body'][] = (string) \Drupal::service('renderer')->renderPlain($build);
break; break;
case 'page_autoreply': case 'page_autoreply':
...@@ -162,7 +162,7 @@ function contact_mail($key, &$message, $params) { ...@@ -162,7 +162,7 @@ function contact_mail($key, &$message, $params) {
$message['body'][] = t("!sender-name (!sender-url) has sent you a message via your contact form at !site-name.", $variables, $options); $message['body'][] = t("!sender-name (!sender-url) has sent you a message via your contact form at !site-name.", $variables, $options);
$message['body'][] = t("If you don't want to receive such emails, you can change your settings at !recipient-edit-url.", $variables, $options); $message['body'][] = t("If you don't want to receive such emails, you can change your settings at !recipient-edit-url.", $variables, $options);
$build = entity_view($contact_message, 'mail', $language->getId()); $build = entity_view($contact_message, 'mail', $language->getId());
$message['body'][] = \Drupal::service('renderer')->renderPlain($build); $message['body'][] = (string) \Drupal::service('renderer')->renderPlain($build);
break; break;
} }
} }
......
...@@ -44,7 +44,7 @@ public function render(Request $request) { ...@@ -44,7 +44,7 @@ public function render(Request $request) {
'#type' => 'contextual_links', '#type' => 'contextual_links',
'#contextual_links' => _contextual_id_to_links($id), '#contextual_links' => _contextual_id_to_links($id),
); );
$rendered[$id] = $this->container->get('renderer')->renderRoot($element); $rendered[$id] = (string) $this->container->get('renderer')->renderRoot($element);
} }
return new JsonResponse($rendered); return new JsonResponse($rendered);
......
...@@ -48,7 +48,7 @@ public function getUntransformedText(EntityInterface $entity, $field_name, $lang ...@@ -48,7 +48,7 @@ public function getUntransformedText(EntityInterface $entity, $field_name, $lang
// Direct text editing is only supported for single-valued fields. // Direct text editing is only supported for single-valued fields.
$field = $entity->getTranslation($langcode)->$field_name; $field = $entity->getTranslation($langcode)->$field_name;
$editable_text = check_markup($field->value, $field->format, $langcode, array(FilterInterface::TYPE_TRANSFORM_REVERSIBLE, FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE)); $editable_text = check_markup($field->value, $field->format, $langcode, array(FilterInterface::TYPE_TRANSFORM_REVERSIBLE, FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE));
$response->addCommand(new GetUntransformedTextCommand($editable_text)); $response->addCommand(new GetUntransformedTextCommand((string) $editable_text));
return $response; return $response;
} }
......
...@@ -288,7 +288,7 @@ function filter_fallback_format() { ...@@ -288,7 +288,7 @@ function filter_fallback_format() {
* FilterInterface::TYPE_HTML_RESTRICTOR is the only type that cannot be * FilterInterface::TYPE_HTML_RESTRICTOR is the only type that cannot be
* skipped. * skipped.
* *
* @return string * @return \Drupal\Component\Utility\SafeStringInterface
* The filtered text. * The filtered text.
* *
* @see filter_process_text() * @see filter_process_text()
......
...@@ -60,7 +60,7 @@ function testCheckMarkupFilterOrder() { ...@@ -60,7 +60,7 @@ function testCheckMarkupFilterOrder() {
$text = "<p>Llamas are <not> awesome!</p>"; $text = "<p>Llamas are <not> awesome!</p>";
$expected_filtered_text = "&lt;p&gt;Llamas are awesome!&lt;/p&gt;"; $expected_filtered_text = "&lt;p&gt;Llamas are awesome!&lt;/p&gt;";
$this->assertIdentical(check_markup($text, 'crazy'), $expected_filtered_text, 'Filters applied in correct order.'); $this->assertEqual(check_markup($text, 'crazy'), $expected_filtered_text, 'Filters applied in correct order.');
} }
/** /**
...@@ -73,14 +73,14 @@ function testCheckMarkupFilterSubset() { ...@@ -73,14 +73,14 @@ function testCheckMarkupFilterSubset() {
$actual_filtered_text = check_markup($text, 'filtered_html', '', array()); $actual_filtered_text = check_markup($text, 'filtered_html', '', array());
$this->verbose("Actual:<pre>$actual_filtered_text</pre>Expected:<pre>$expected_filtered_text</pre>"); $this->verbose("Actual:<pre>$actual_filtered_text</pre>Expected:<pre>$expected_filtered_text</pre>");
$this->assertIdentical( $this->assertEqual(
$actual_filtered_text, $actual_filtered_text,
$expected_filtered_text, $expected_filtered_text,
'Expected filter result.' 'Expected filter result.'
); );
$actual_filtered_text_without_html_generators = check_markup($text, 'filtered_html', '', array(FilterInterface::TYPE_MARKUP_LANGUAGE)); $actual_filtered_text_without_html_generators = check_markup($text, 'filtered_html', '', array(FilterInterface::TYPE_MARKUP_LANGUAGE));
$this->verbose("Actual:<pre>$actual_filtered_text_without_html_generators</pre>Expected:<pre>$expected_filter_text_without_html_generators</pre>"); $this->verbose("Actual:<pre>$actual_filtered_text_without_html_generators</pre>Expected:<pre>$expected_filter_text_without_html_generators</pre>");
$this->assertIdentical( $this->assertEqual(
$actual_filtered_text_without_html_generators, $actual_filtered_text_without_html_generators,
$expected_filter_text_without_html_generators, $expected_filter_text_without_html_generators,
'Expected filter result when skipping FilterInterface::TYPE_MARKUP_LANGUAGE filters.' 'Expected filter result when skipping FilterInterface::TYPE_MARKUP_LANGUAGE filters.'
...@@ -91,7 +91,7 @@ function testCheckMarkupFilterSubset() { ...@@ -91,7 +91,7 @@ function testCheckMarkupFilterSubset() {
// most extensive test possible. // most extensive test possible.
$actual_filtered_text_without_html_generators = check_markup($text, 'filtered_html', '', array(FilterInterface::TYPE_HTML_RESTRICTOR, FilterInterface::TYPE_MARKUP_LANGUAGE)); $actual_filtered_text_without_html_generators = check_markup($text, 'filtered_html', '', array(FilterInterface::TYPE_HTML_RESTRICTOR, FilterInterface::TYPE_MARKUP_LANGUAGE));
$this->verbose("Actual:<pre>$actual_filtered_text_without_html_generators</pre>Expected:<pre>$expected_filter_text_without_html_generators</pre>");