Skip to content
Snippets Groups Projects
Commit 7b10e666 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #2529560 by John Cook, dawehner, Xano, lauriii, tim.plunkett, Wim Leers,...

Issue #2529560 by John Cook, dawehner, Xano, lauriii, tim.plunkett, Wim Leers, nlisgo, Crell, plach, Fabianx: Expand support for link objects
parent 02569d15
No related branches found
No related tags found
No related merge requests found
Showing
with 164 additions and 25 deletions
......@@ -7,13 +7,17 @@
namespace Drupal\Core;
use Drupal\Core\Render\RenderableInterface;
use Drupal\Core\Routing\LinkGeneratorTrait;
/**
* Defines an object that holds information about a link.
*/
class Link {
class Link implements RenderableInterface {
/**
* @deprecated in Drupal 8.0.x-dev, will be removed before Drupal 9.0.0.
*/
use LinkGeneratorTrait;
/**
......@@ -44,7 +48,7 @@ public function __construct($text, Url $url) {
}
/**
* Creates a link object from a given route name and parameters.
* Creates a Link object from a given route name and parameters.
*
* @param string $text
* The text of the link.
......@@ -75,6 +79,20 @@ public static function createFromRoute($text, $route_name, $route_parameters = a
return new static($text, new Url($route_name, $route_parameters, $options));
}
/**
* Creates a Link object from a given Url object.
*
* @param string $text
* The text of the link.
* @param \Drupal\Core\Url $url
* The Url to create the link for.
*
* @return static
*/
public static function fromTextAndUrl($text, Url $url) {
return new static($text, $url);
}
/**
* Returns the text of the link.
*
......@@ -130,9 +148,23 @@ public function setUrl(Url $url) {
* 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);
}
/**
* {@inheritdoc}
*/
public function toRenderable() {
return [
'#type' => 'link',
'#url' => $this->url,
'#title' => $this->text,
];
}
}
<?php
/**
* @file
* Contains \Drupal\Core\Render\RenderableInterface.
*/
namespace Drupal\Core\Render;
/**
* Defines an object which can be rendered by the Render API.
*/
interface RenderableInterface {
/**
* Returns a render array representation of the object.
*
* @return mixed[]
* A render array.
*/
public function toRenderable();
}
......@@ -15,6 +15,7 @@
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\SafeStringInterface;
use Drupal\Core\Render\RenderableInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Routing\UrlGeneratorInterface;
use Drupal\Core\Theme\ThemeManagerInterface;
......@@ -386,7 +387,10 @@ public function escapeFilter(\Twig_Environment $env, $arg, $strategy = 'html', $
$return = (string) $arg;
}
elseif (is_object($arg)) {
if (method_exists($arg, '__toString')) {
if ($arg instanceof RenderableInterface) {
$arg = $arg->toRenderable();
}
elseif (method_exists($arg, '__toString')) {
$return = (string) $arg;
}
// You can't throw exceptions in the magic PHP __toString methods, see
......@@ -461,7 +465,10 @@ public function renderVar($arg) {
}
if (is_object($arg)) {
if (method_exists($arg, '__toString')) {
if ($arg instanceof RenderableInterface) {
$arg = $arg->toRenderable();
}
elseif (method_exists($arg, '__toString')) {
return (string) $arg;
}
// You can't throw exceptions in the magic PHP __toString methods, see
......
......@@ -10,6 +10,7 @@
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Link;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Routing\UrlGeneratorInterface;
use Drupal\Core\Session\AccountInterface;
......@@ -39,13 +40,6 @@ class ImageFormatter extends ImageFormatterBase implements ContainerFactoryPlugi
*/
protected $currentUser;
/**
* The link generator.
*
* @var \Drupal\Core\Utility\LinkGeneratorInterface
*/
protected $linkGenerator;
/**
* The image style entity storage.
*
......@@ -72,13 +66,10 @@ class ImageFormatter extends ImageFormatterBase implements ContainerFactoryPlugi
* Any third party settings settings.
* @param \Drupal\Core\Session\AccountInterface $current_user
* The current user.
* @param \Drupal\Core\Utility\LinkGeneratorInterface $link_generator
* The link generator service.
*/
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, AccountInterface $current_user, LinkGeneratorInterface $link_generator, EntityStorageInterface $image_style_storage) {
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, AccountInterface $current_user, EntityStorageInterface $image_style_storage) {
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
$this->currentUser = $current_user;
$this->linkGenerator = $link_generator;
$this->imageStyleStorage = $image_style_storage;
}
......@@ -95,7 +86,6 @@ public static function create(ContainerInterface $container, array $configuratio
$configuration['view_mode'],
$configuration['third_party_settings'],
$container->get('current_user'),
$container->get('link_generator'),
$container->get('entity.manager')->getStorage('image_style')
);
}
......@@ -115,17 +105,20 @@ public static function defaultSettings() {
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
$image_styles = image_style_options(FALSE);
$element['image_style'] = array(
$description_link = Link::fromTextAndUrl(
$this->t('Configure Image Styles'),
Url::fromRoute('entity.image_style.collection')
);
$element['image_style'] = [
'#title' => t('Image style'),
'#type' => 'select',
'#default_value' => $this->getSetting('image_style'),
'#empty_option' => t('None (original image)'),
'#options' => $image_styles,
'#description' => array(
'#markup' => $this->linkGenerator->generate($this->t('Configure Image Styles'), new Url('entity.image_style.collection')),
'#access' => $this->currentUser->hasPermission('administer image styles'),
),
);
'#description' => $description_link->toRenderable() + [
'#access' => $this->currentUser->hasPermission('administer image styles')
],
];
$link_types = array(
'content' => t('Content'),
'file' => t('File'),
......
......@@ -13,6 +13,7 @@
use Drupal\Core\Entity\Query\QueryFactory;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Link;
use Drupal\Core\Menu\MenuLinkManagerInterface;
use Drupal\Core\Menu\MenuLinkTreeElement;
use Drupal\Core\Menu\MenuLinkTreeInterface;
......@@ -353,12 +354,12 @@ protected function buildOverviewTreeForm($tree, $delta) {
$id = 'menu_plugin_id:' . $link->getPluginId();
$form[$id]['#item'] = $element;
$form[$id]['#attributes'] = $link->isEnabled() ? array('class' => array('menu-enabled')) : array('class' => array('menu-disabled'));
$form[$id]['title']['#markup'] = $this->linkGenerator->generate($link->getTitle(), $link->getUrlObject());
$form[$id]['title'] = Link::fromTextAndUrl($link->getTitle(), $link->getUrlObject())->toRenderable();
if (!$link->isEnabled()) {
$form[$id]['title']['#markup'] .= ' (' . $this->t('disabled') . ')';
$form[$id]['title']['#suffix'] = ' (' . $this->t('disabled') . ')';
}
elseif (($url = $link->getUrlObject()) && $url->isRouted() && $url->getRouteName() == 'user.page') {
$form[$id]['title']['#markup'] .= ' (' . $this->t('logged in users only') . ')';
$form[$id]['title']['#suffix'] = ' (' . $this->t('logged in users only') . ')';
}
$form[$id]['enabled'] = array(
......
......@@ -137,4 +137,12 @@ public function testTwigAttachLibrary() {
$this->assertRaw('ckeditor.js');
}
/**
* Tests the rendering of renderables.
*/
public function testRenderable() {
$this->drupalGet('/twig-theme-test/renderable');
$this->assertRaw('<div>Example markup</div>');
}
}
<?php
/**
* @file
* Contains \Drupal\twig_theme_test\ExampleRenderable.
*/
namespace Drupal\twig_theme_test;
use Drupal\Core\Render\RenderableInterface;
/**
* Provides an example implementation of the RenderableInterface.
*/
class ExampleRenderable implements RenderableInterface {
/**
* {@inheritdoc}
*/
public function toRenderable() {
return [
'#markup' => 'Example markup',
];
}
}
......@@ -99,4 +99,14 @@ public function registryLoaderRender() {
return array('#theme' => 'twig_registry_loader_test');
}
/**
* Controller for testing a renderable inside a template.
*/
public function renderable() {
return [
'#theme' => 'twig_theme_test_renderable',
'#renderable' => new ExampleRenderable()
];
}
}
<div>{{ renderable }}</div>
......@@ -62,6 +62,12 @@ function twig_theme_test_theme($existing, $type, $theme, $path) {
'variables' => array(),
'template' => 'twig_theme_test.attach_library',
);
$items['twig_theme_test_renderable'] = array(
'variables' => array(
'renderable' => NULL,
),
'template' => 'twig_theme_test.renderable',
);
return $items;
}
......
......@@ -62,3 +62,10 @@ twig_theme_test_registry_loader:
no_cache: TRUE
requirements:
_access: 'TRUE'
twig_theme_test_renderable:
path: '/twig-theme-test/renderable'
defaults:
_controller: '\Drupal\twig_theme_test\TwigThemeTestController::renderable'
requirements:
_access: 'TRUE'
......@@ -8,6 +8,7 @@
namespace Drupal\Tests\Core\Template;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Render\RenderableInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Template\TwigEnvironment;
use Drupal\Core\Template\TwigExtension;
......@@ -152,6 +153,30 @@ public function testSafeJoin() {
$this->assertEquals('&lt;em&gt;will be escaped&lt;/em&gt;<br/><em>will be markup</em><br/><strong>will be rendered</strong>', $result);
}
/**
* @dataProvider providerTestRenderVar
*/
public function testRenderVar($result, $input) {
$renderer = $this->prophesize(RendererInterface::class);
$renderer->render($result += ['#printed' => FALSE])->willReturn('Rendered output');
$renderer = $renderer->reveal();
$twig_extension = new TwigExtension($renderer);
$this->assertEquals('Rendered output', $twig_extension->renderVar($input));
}
public function providerTestRenderVar() {
$data = [];
$renderable = $this->prophesize(RenderableInterface::class);
$render_array = ['#type' => 'test', '#var' => 'giraffe'];
$renderable->toRenderable()->willReturn($render_array);
$data['renderable'] = [$render_array, $renderable->reveal()];
return $data;
}
}
class TwigExtensionTestString {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment