Commit a7254dba authored by effulgentsia's avatar effulgentsia

Issue #2568977 by alexpott, dawehner, pwolanin, Wim Leers: Replace...

Issue #2568977 by alexpott, dawehner, pwolanin, Wim Leers: Replace SafeMarkup::format() in the link generator - it's a bad example to everyone
parent 108e038e
......@@ -542,20 +542,16 @@ public static function linkGenerator() {
* The link text for the anchor tag.
* @param \Drupal\Core\Url $url
* The URL object used for the link.
* @param bool $collect_bubbleable_metadata
* (optional) Defaults to FALSE. When TRUE, both the generated URL and its
* associated bubbleable metadata are returned.
*
* @return string|\Drupal\Core\GeneratedLink
* An HTML string containing a link to the given route and parameters.
* When $collect_bubbleable_metadata is TRUE, a GeneratedLink object is
* returned, containing the generated link plus bubbleable metadata.
* @return \Drupal\Core\GeneratedLink
* A GeneratedLink object containing a link to the given route and
* parameters and bubbleable metadata.
*
* @see \Drupal\Core\Utility\LinkGeneratorInterface::generate()
* @see \Drupal\Core\Url
*/
public static function l($text, Url $url, $collect_bubbleable_metadata = FALSE) {
return static::getContainer()->get('link_generator')->generate($text, $url, $collect_bubbleable_metadata);
public static function l($text, Url $url) {
return static::getContainer()->get('link_generator')->generate($text, $url);
}
/**
......
......@@ -7,6 +7,7 @@
namespace Drupal\Core;
use Drupal\Component\Utility\SafeStringInterface;
use Drupal\Core\Render\BubbleableMetadata;
/**
......@@ -15,7 +16,7 @@
* Note: not to be confused with \Drupal\Core\Link, which is for passing around
* ungenerated links (typically link text + route name + route parameters).
*/
class GeneratedLink extends BubbleableMetadata {
class GeneratedLink extends BubbleableMetadata implements SafeStringInterface {
/**
* The HTML string value containing a link.
......@@ -46,4 +47,18 @@ public function setGeneratedLink($generated_link) {
return $this;
}
/**
* {@inheritdoc}
*/
public function __toString() {
return (string) $this->generatedLink;
}
/**
* {@inheritdoc}
*/
public function jsonSerialize() {
return $this->__toString();
}
}
......@@ -140,20 +140,14 @@ public function setUrl(Url $url) {
/**
* Generates the HTML for this Link object.
*
* @param bool $collect_bubbleable_metadata
* (optional) Defaults to FALSE. When TRUE, both the generated link and its
* associated bubbleable metadata are returned.
*
* @return string|\Drupal\Core\GeneratedLink
* @return \Drupal\Core\GeneratedLink
* The link HTML markup.
* When $collect_bubbleable_metadata is TRUE, a GeneratedLink object is
* returned, containing the generated link plus bubbleable metadata.
*
* @deprecated in Drupal 8.0.x-dev, will be removed before Drupal 9.0.0. Use
* self::toRenderable() instead.
*/
public function toString($collect_bubbleable_metadata = FALSE) {
return $this->getLinkGenerator()->generateFromLink($this, $collect_bubbleable_metadata);
public function toString() {
return $this->getLinkGenerator()->generateFromLink($this);
}
/**
......
......@@ -440,7 +440,11 @@ function hook_system_breadcrumb_alter(\Drupal\Core\Breadcrumb\Breadcrumb &$bread
* exposed as the 'link_generator' service or a link generated by _l(). If the
* link is a "route link", 'route_name' will be set, otherwise 'path' will be
* set. The following keys can be altered:
* - text: The link text for the anchor tag as a translated string.
* - text: The link text for the anchor tag. If the hook implementation
* changes this text it needs to preserve the safeness of the original text.
* Using t() or \Drupal\Component\Utility\SafeMarkup::format() with
* @placeholder is recommended as this will escape the original text if
* necessary. If the resulting text is not marked safe it will be escaped.
* - url_is_active: Whether or not the link points to the currently active
* URL.
* - url: The \Drupal\Core\Url object.
......@@ -468,7 +472,7 @@ function hook_system_breadcrumb_alter(\Drupal\Core\Breadcrumb\Breadcrumb &$bread
function hook_link_alter(&$variables) {
// Add a warning to the end of route links to the admin section.
if (isset($variables['route_name']) && strpos($variables['route_name'], 'admin') !== FALSE) {
$variables['text'] .= ' (Warning!)';
$variables['text'] = t('@text (Warning!)', ['@text' => $variables['text']]);
}
}
......
......@@ -82,7 +82,7 @@ public static function preRenderLink($element) {
$options = NestedArray::mergeDeep($element['#url']->getOptions(), $element['#options']);
/** @var \Drupal\Core\Utility\LinkGenerator $link_generator */
$link_generator = \Drupal::service('link_generator');
$generated_link = $link_generator->generate($element['#title'], $element['#url']->setOptions($options), TRUE);
$generated_link = $link_generator->generate($element['#title'], $element['#url']->setOptions($options));
$element['#markup'] = $generated_link->getGeneratedLink();
$generated_link->merge(BubbleableMetadata::createFromRenderArray($element))
->applyTo($element);
......
......@@ -35,8 +35,9 @@ trait LinkGeneratorTrait {
* @see \Drupal\Core\Utility\LinkGeneratorInterface::generate() for details
* on the arguments, usage, and possible exceptions.
*
* @return string
* An HTML string containing a link to the given route and parameters.
* @return \Drupal\Core\GeneratedLink
* A GeneratedLink object containing a link to the given route and
* parameters and bubbleable metadata.
*/
protected function l($text, Url $url) {
return $this->getLinkGenerator()->generate($text, $url);
......
......@@ -8,6 +8,7 @@
namespace Drupal\Core\Utility;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\SafeStringInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
......@@ -64,8 +65,8 @@ public function __construct(UrlGeneratorInterface $url_generator, ModuleHandlerI
/**
* {@inheritdoc}
*/
public function generateFromLink(Link $link, $collect_bubbleable_metadata = FALSE) {
return $this->generate($link->getText(), $link->getUrl(), $collect_bubbleable_metadata);
public function generateFromLink(Link $link) {
return $this->generate($link->getText(), $link->getUrl());
}
/**
......@@ -80,14 +81,18 @@ public function generateFromLink(Link $link, $collect_bubbleable_metadata = FALS
*
* @see system_page_attachments()
*/
public function generate($text, Url $url, $collect_bubbleable_metadata = FALSE) {
public function generate($text, Url $url) {
// Performance: avoid Url::toString() needing to retrieve the URL generator
// service from the container.
$url->setUrlGenerator($this->urlGenerator);
if (is_array($text)) {
$text = $this->renderer->render($text);
}
// Start building a structured representation of our link to be altered later.
$variables = array(
'text' => is_array($text) ? $this->renderer->render($text) : $text,
'text' => $text,
'url' => $url,
'options' => $url->getOptions(),
);
......@@ -149,21 +154,26 @@ public function generate($text, Url $url, $collect_bubbleable_metadata = FALSE)
unset($variables['options']['attributes']);
$url->setOptions($variables['options']);
if (!$collect_bubbleable_metadata) {
$url_string = $url->toString($collect_bubbleable_metadata);
// External URLs can not have cacheable metadata.
if ($url->isExternal()) {
$generated_link = new GeneratedLink();
$attributes['href'] = $url->toString(FALSE);
}
else {
$generated_url = $url->toString($collect_bubbleable_metadata);
$url_string = $generated_url->getGeneratedUrl();
$generated_url = $url->toString(TRUE);
$generated_link = GeneratedLink::createFromObject($generated_url);
// The result of the URL generator is a plain-text URL to use as the href
// attribute, and it is escaped by \Drupal\Core\Template\Attribute.
$attributes['href'] = $generated_url->getGeneratedUrl();
}
// The result of the URL generator is a plain-text URL to use as the href
// attribute, and it is escaped by \Drupal\Core\Template\Attribute.
$attributes['href'] = $url_string;
$result = SafeMarkup::format('<a@attributes>@text</a>', array('@attributes' => new Attribute($attributes), '@text' => $variables['text']));
return $collect_bubbleable_metadata ? $generated_link->setGeneratedLink($result) : $result;
if (!SafeMarkup::isSafe($variables['text'])) {
$variables['text'] = Html::escape($variables['text']);
}
$attributes = new Attribute($attributes);
// This is safe because Attribute does escaping and $variables['text'] is
// either rendered or escaped.
return $generated_link->setGeneratedLink('<a' . $attributes . '>' . $variables['text'] . '</a>');
}
}
......@@ -60,14 +60,10 @@ interface LinkGeneratorInterface {
* class will be applied to the link. It is important to use this
* sparingly since it is usually unnecessary and requires extra
* processing.
* @param bool $collect_bubbleable_metadata
* (optional) Defaults to FALSE. When TRUE, both the generated link and its
* associated bubbleable metadata are returned.
*
* @return string|\Drupal\Core\GeneratedLink
* An HTML string containing a link to the given route and parameters.
* When $collect_bubbleable_metadata is TRUE, a GeneratedLink object is
* returned, containing the generated link plus bubbleable metadata.
* @return \Drupal\Core\GeneratedLink
* A GeneratedLink object containing a link to the given route and
* parameters and bubbleable metadata.
*
* @throws \Symfony\Component\Routing\Exception\RouteNotFoundException
* Thrown when the named route doesn't exist.
......@@ -77,22 +73,18 @@ interface LinkGeneratorInterface {
* Thrown when a parameter value for a placeholder is not correct because it
* does not match the requirement.
*/
public function generate($text, Url $url, $collect_bubbleable_metadata = FALSE);
public function generate($text, Url $url);
/**
* Renders a link from a link object.
*
* @param \Drupal\Core\Link $link
* A link object to convert to a string.
* @param bool $collect_bubbleable_metadata
* (optional) Defaults to FALSE. When TRUE, both the generated link and its
* associated bubbleable metadata are returned.
*
* @return string|\Drupal\Core\GeneratedLink
* An HTML string containing a link to the given route and parameters.
* When $collect_bubbleable_metadata is TRUE, a GeneratedLink object is
* returned, containing the generated link plus bubbleable metadata.
* @return \Drupal\Core\GeneratedLink
* A GeneratedLink object containing a link to the given route and
* parameters and bubbleable metadata.
*/
public function generateFromLink(Link $link, $collect_bubbleable_metadata = FALSE);
public function generateFromLink(Link $link);
}
<?php
/**
* @file
* Contains \Drupal\system\Tests\Utility\LinkGenerationTest.
*/
namespace Drupal\system\Tests\Utility;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Url;
use Drupal\simpletest\KernelTestBase;
/**
* Tests link generation with hooks.
*
* @group Utility
*/
class LinkGenerationTest extends KernelTestBase {
public static $modules = ['link_generation_test'];
/**
* Tests how hook_link_alter() can affect escaping of the link text.
*/
function testHookLinkAlter() {
$url = Url::fromUri('http://example.com');
$renderer = \Drupal::service('renderer');
$link = $renderer->executeInRenderContext(new RenderContext(), function () use ($url) {
return \Drupal::l(['#markup' => '<em>link with markup</em>'], $url);
});
$this->setRawContent($link);
$this->assertTrue(SafeMarkup::isSafe($link), 'The output of link generation is marked safe as it is a link.');
// Ensure the content of the link is not escaped.
$this->assertRaw('<em>link with markup</em>');
// Test just adding text to an already safe string.
\Drupal::state()->set('link_generation_test_link_alter', TRUE);
$link = $renderer->executeInRenderContext(new RenderContext(), function () use ($url) {
return \Drupal::l(['#markup' => '<em>link with markup</em>'], $url);
});
$this->setRawContent($link);
$this->assertTrue(SafeMarkup::isSafe($link), 'The output of link generation is marked safe as it is a link.');
// Ensure the content of the link is escaped.
$this->assertEscaped('<em>link with markup</em> <strong>Test!</strong>');
// Test passing a safe string to t().
\Drupal::state()->set('link_generation_test_link_alter_safe', TRUE);
$link = $renderer->executeInRenderContext(new RenderContext(), function () use ($url) {
return \Drupal::l(['#markup' => '<em>link with markup</em>'], $url);
});
$this->setRawContent($link);
$this->assertTrue(SafeMarkup::isSafe($link), 'The output of link generation is marked safe as it is a link.');
// Ensure the content of the link is escaped.
$this->assertRaw('<em>link with markup</em> <strong>Test!</strong>');
// Test passing an unsafe string to t().
$link = $renderer->executeInRenderContext(new RenderContext(), function () use ($url) {
return \Drupal::l('<em>link with markup</em>', $url);
});
$this->setRawContent($link);
$this->assertTrue(SafeMarkup::isSafe($link), 'The output of link generation is marked safe as it is a link.');
// Ensure the content of the link is escaped.
$this->assertEscaped('<em>link with markup</em>');
$this->assertRaw('<strong>Test!</strong>');
}
}
name: 'Link generation test support'
type: module
description: 'Test hooks fired in link generation.'
package: Testing
version: VERSION
core: 8.x
<?php
/**
* @file
* Helper module for the link generation tests.
*/
/**
* Implements hook_link_alter().
*/
function link_generation_test_link_alter(&$variables) {
if (\Drupal::state()->get('link_generation_test_link_alter', FALSE)) {
// Add a text to the end of links.
if (\Drupal::state()->get('link_generation_test_link_alter_safe', FALSE)) {
$variables['text'] = t('@text <strong>Test!</strong>', ['@text' => $variables['text']]);
}
else {
$variables['text'] .= ' <strong>Test!</strong>';
}
}
}
......@@ -1305,8 +1305,9 @@ public function renderText($alter) {
}
// Preserve whether or not the string is safe. Since $suffix comes from
// \Drupal::l(), it is safe to append.
if ($value_is_safe) {
// \Drupal::l(), it is safe to append. Use SafeMarkup::isSafe() here because
// renderAsLink() can return both safe and unsafe values.
if (SafeMarkup::isSafe($value)) {
return ViewsRenderPipelineSafeString::create($value . $suffix);
}
else {
......@@ -1531,19 +1532,20 @@ protected function renderAsLink($alter, $text, $tokens) {
// Build the link based on our altered Url object, adding on the optional
// prefix and suffix
$value = '';
$render = [
'#type' => 'link',
'#title' => $text,
'#url' => $final_url,
];
if (!empty($alter['prefix'])) {
$value .= Xss::filterAdmin($this->viewsTokenReplace($alter['prefix'], $tokens));
$render['#prefix'] = $this->viewsTokenReplace($alter['prefix'], $tokens);
}
$value .= $this->linkGenerator()->generate($text, $final_url);
if (!empty($alter['suffix'])) {
$value .= Xss::filterAdmin($this->viewsTokenReplace($alter['suffix'], $tokens));
$render['#suffix'] = $this->viewsTokenReplace($alter['suffix'], $tokens);
}
return $this->getRenderer()->render($render);
return $value;
}
/**
......
......@@ -7,7 +7,10 @@
namespace Drupal\Tests\views\Unit\Plugin\field;
use Drupal\Core\GeneratedUrl;
use Drupal\Core\Language\Language;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Render\SafeString;
use Drupal\Core\Url;
use Drupal\Core\Utility\LinkGenerator;
use Drupal\Core\Utility\LinkGeneratorInterface;
......@@ -174,6 +177,22 @@ protected function setUpUrlIntegrationServices() {
\Drupal::getContainer()->set('unrouted_url_assembler', $this->unroutedUrlAssembler);
$this->linkGenerator = new LinkGenerator($this->urlGenerator, $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface'), $this->renderer);
$this->renderer
->method('render')
->willReturnCallback(
// Pretend to do a render.
function (&$elements, $is_root_call = FALSE) {
// Mock the ability to theme links
$link = $this->linkGenerator->generate($elements['#title'], $elements['#url']);
if (isset($elements['#prefix'])) {
$link = $elements['#prefix'] . $link;
}
if (isset($elements['#suffix'])) {
$link = $link . $elements['#suffix'];
}
return SafeString::create($link);
}
);
}
/**
......@@ -229,7 +248,7 @@ public function testRenderAsLinkWithPathAndOptions($path, $alter, $link_html, $f
$row = new ResultRow(['key' => 'value']);
$result = $field->advancedRender($row);
$this->assertEquals($final_html, $result);
$this->assertEquals($final_html, (string) $result);
}
/**
......@@ -308,8 +327,8 @@ public function testRenderAsLinkWithUrlAndOptions(Url $url, $alter, Url $expecte
$this->urlGenerator->expects($this->once())
->method('generateFromRoute')
->with($expected_url->getRouteName(), $expected_url->getRouteParameters(), $expected_url_options)
->willReturn($url_path);
->with($expected_url->getRouteName(), $expected_url->getRouteParameters(), $expected_url_options, TRUE)
->willReturn((new GeneratedUrl())->setGeneratedUrl($url_path));
$result = $field->advancedRender($row);
$this->assertEquals($final_html, $result);
......
......@@ -121,13 +121,15 @@ public function reportFields() {
public function reportPlugins() {
$rows = Views::pluginList();
foreach ($rows as &$row) {
$views = [];
// Link each view name to the view itself.
foreach ($row['views'] as $row_name => $view) {
$row['views'][$row_name] = $this->l($view, new Url('entity.view.edit_form', array('view' => $view)));
$views[] = $this->l($view, new Url('entity.view.edit_form', array('view' => $view)));
}
unset($row['views']);
$row['views']['data'] = [
'#theme' => 'item_list',
'#items' => $row['views'],
'#items' => $views,
'#context' => ['list_style' => 'comma-list'],
];
}
......
......@@ -7,6 +7,7 @@
namespace Drupal\Tests\Core\Utility {
use Drupal\Component\Utility\SafeStringInterface;
use Drupal\Core\GeneratedUrl;
use Drupal\Core\Language\Language;
use Drupal\Core\Link;
......@@ -111,8 +112,7 @@ public function testGenerateHrefs($route_name, array $parameters, $absolute, $ex
$this->urlGenerator->expects($this->once())
->method('generateFromRoute')
->with($route_name, $parameters, array('absolute' => $absolute) + $this->defaultOptions)
->will($this->returnValue($expected_url));
->willReturn((new GeneratedUrl())->setGeneratedUrl($expected_url));
$this->moduleHandler->expects($this->once())
->method('alter');
......@@ -133,7 +133,7 @@ public function testGenerate() {
$this->urlGenerator->expects($this->once())
->method('generateFromRoute')
->with('test_route_1', array(), array('fragment' => 'the-fragment') + $this->defaultOptions)
->will($this->returnValue('/test-route-1#the-fragment'));
->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-1#the-fragment'));
$this->moduleHandler->expects($this->once())
->method('alter')
......@@ -197,7 +197,7 @@ public function testGenerateUrlWithQuotes() {
$this->urlAssembler->expects($this->once())
->method('assemble')
->with('base:example', array('query' => array('foo' => '"bar"', 'zoo' => 'baz')) + $this->defaultOptions)
->will($this->returnValue('/example?foo=%22bar%22&zoo=baz'));
->willReturn((new GeneratedUrl())->setGeneratedUrl('/example?foo=%22bar%22&zoo=baz'));
$path_validator = $this->getMock('Drupal\Core\Path\PathValidatorInterface');
$container_builder = new ContainerBuilder();
......@@ -228,9 +228,7 @@ public function testGenerateAttributes() {
$this->urlGenerator->expects($this->once())
->method('generateFromRoute')
->with('test_route_1', array(), $this->defaultOptions)
->will($this->returnValue(
'/test-route-1'
));
->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-1'));
// Test that HTML attributes are added to the anchor.
$url = new Url('test_route_1', array(), array(
......@@ -255,9 +253,7 @@ public function testGenerateQuery() {
$this->urlGenerator->expects($this->once())
->method('generateFromRoute')
->with('test_route_1', array(), array('query' => array('test' => 'value')) + $this->defaultOptions)
->will($this->returnValue(
'/test-route-1?test=value'
));
->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-1?test=value'));
$url = new Url('test_route_1', array(), array(
'query' => array('test' => 'value'),
......@@ -280,9 +276,7 @@ public function testGenerateParametersAsQuery() {
$this->urlGenerator->expects($this->once())
->method('generateFromRoute')
->with('test_route_1', array('test' => 'value'), $this->defaultOptions)
->will($this->returnValue(
'/test-route-1?test=value'
));
->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-1?test=value'));
$url = new Url('test_route_1', array('test' => 'value'), array());
$url->setUrlGenerator($this->urlGenerator);
......@@ -303,10 +297,7 @@ public function testGenerateOptions() {
$this->urlGenerator->expects($this->once())
->method('generateFromRoute')
->with('test_route_1', array(), array('key' => 'value') + $this->defaultOptions)
->will($this->returnValue(
'/test-route-1?test=value'
));
->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-1?test=value'));
$url = new Url('test_route_1', array(), array(
'key' => 'value',
));
......@@ -328,9 +319,7 @@ public function testGenerateXss() {
$this->urlGenerator->expects($this->once())
->method('generateFromRoute')
->with('test_route_4', array(), $this->defaultOptions)
->will($this->returnValue(
'/test-route-4'
));
->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-4'));
// Test that HTML link text is escaped by default.
$url = new Url('test_route_4');
......@@ -348,15 +337,11 @@ public function testGenerateWithHtml() {
$this->urlGenerator->expects($this->at(0))
->method('generateFromRoute')
->with('test_route_5', array(), $this->defaultOptions)
->will($this->returnValue(
'/test-route-5'
));
->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-5'));
$this->urlGenerator->expects($this->at(1))
->method('generateFromRoute')
->with('test_route_5', array(), $this->defaultOptions)
->will($this->returnValue(
'/test-route-5'
));
->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-5'));
// Test that HTML tags are stripped from the 'title' attribute.
$url = new Url('test_route_5', array(), array(
......@@ -394,11 +379,18 @@ public function testGenerateWithHtml() {
public function testGenerateActive() {
$this->urlGenerator->expects($this->exactly(5))
->method('generateFromRoute')
->will($this->returnValueMap(array(
array('test_route_1', array(), FALSE, '/test-route-1'),
array('test_route_3', array(), FALSE, '/test-route-3'),
array('test_route_4', array('object' => '1'), FALSE, '/test-route-4/1'),
)));
->willReturnCallback(function($name, $parameters = array(), $options = array(), $collect_bubbleable_metadata = FALSE) {
switch ($name) {
case 'test_route_1':
return (new GeneratedUrl())->setGeneratedUrl('/test-route-1');
case 'test_route_3':
return (new GeneratedUrl())->setGeneratedUrl('/test-route-3');
case 'test_route_4':
if ($parameters['object'] == '1') {
return (new GeneratedUrl())->setGeneratedUrl('/test-route-4/1');
}
}
});
$this->urlGenerator->expects($this->exactly(4))
->method('getPathFromRoute')
......@@ -479,7 +471,6 @@ public function testGenerateBubbleableMetadata() {
$this->urlGenerator->expects($this->any())
->method('generateFromRoute')
->will($this->returnValueMap([
['test_route_1', [], $options, FALSE, '/test-route-1'],
['test_route_1', [], $options, TRUE, (new GeneratedUrl())->setGeneratedUrl('/test-route-1')],
]));
......@@ -488,16 +479,16 @@ public function testGenerateBubbleableMetadata() {
$expected_link_markup = '<a href="/test-route-1">Test</a>';
// Test ::generate().
$this->assertSame($expected_link_markup, $this->linkGenerator->generate('Test', $url));
$generated_link = $this->linkGenerator->generate('Test', $url, TRUE);
$this->assertSame($expected_link_markup, $generated_link->getGeneratedLink());
$this->assertSame($expected_link_markup, (string) $this->linkGenerator->generate('Test', $url));
$generated_link = $this->linkGenerator->generate('Test', $url);
$this->assertSame($expected_link_markup, (string) $generated_link->getGeneratedLink());
$this->assertInstanceOf('\Drupal\Core\Render\BubbleableMetadata', $generated_link);
// Test ::generateFromLink().
$link = new Link('Test', $url);
$this->assertSame($expected_link_markup, $this->linkGenerator->generateFromLink($link));
$generated_link = $this->linkGenerator->generateFromLink($link, TRUE);
$this->assertSame($expected_link_markup, $generated_link->getGeneratedLink());
$this->assertSame($expected_link_markup, (string) $this->linkGenerator->generateFromLink($link));
$generated_link = $this->linkGenerator->generateFromLink($link);
$this->assertSame($expected_link_markup, (string) $generated_link->getGeneratedLink());
$this->assertInstanceOf('\Drupal\Core\Render\BubbleableMetadata', $generated_link);
}
......@@ -508,12 +499,12 @@ public function testGenerateBubbleableMetadata() {
* An associative array of link properties, with the following keys:
* - attributes: optional array of HTML attributes that should be present.
* - content: optional link content.
* @param string $html
* @param \Drupal\Component\Utility\SafeStringInterface $html
* The HTML to check.
* @param int $count
* How many times the link should be present in the HTML. Defaults to 1.
*/
public static function assertLink(array $properties, $html, $count = 1) {
public static function assertLink(array $properties, SafeStringInterface $html, $count = 1) {
// Provide default values.
$properties += array('attributes' => array());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment