Commit a17498c5 authored by catch's avatar catch

Issue #2387019 by dawehner, larowlan: String field formatters cannot link to their parent entity

parent 47381094
......@@ -225,6 +225,13 @@ field.widget.settings.checkbox:
type: boolean
label: 'Use field label instead of the "On value" as label'
field.formatter.settings.string:
type: mapping
mapping:
link_to_entity:
type: boolean
label: 'Link to the entity'
field.formatter.settings.number_decimal:
type: mapping
label: 'Number decimal display format settings'
......
<?php
/**
* @file
* Contains \Drupal\Core\Field\Plugin\Field\FieldFormatter\BasicStringFormatter.
*/
namespace Drupal\Core\Field\Plugin\Field\FieldFormatter;
use Drupal\Component\Utility\String;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Field\FieldItemListInterface;
/**
* Plugin implementation of the 'basic_string' formatter.
*
* @FieldFormatter(
* id = "basic_string",
* label = @Translation("Plain text"),
* field_types = {
* "string_long",
* "email"
* },
* quickedit = {
* "editor" = "plain_text"
* }
* )
*/
class BasicStringFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items) {
$elements = array();
foreach ($items as $delta => $item) {
// The text value has no text format assigned to it, so the user input
// should equal the output, including newlines.
$elements[$delta] = array('#markup' => nl2br(String::checkPlain($item->value)));
}
return $elements;
}
}
......@@ -8,8 +8,13 @@
namespace Drupal\Core\Field\Plugin\Field\FieldFormatter;
use Drupal\Component\Utility\String;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Plugin implementation of the 'string' formatter.
......@@ -19,15 +24,93 @@
* label = @Translation("Plain text"),
* field_types = {
* "string",
* "string_long",
* "email"
* },
* quickedit = {
* "editor" = "plain_text"
* }
* )
*/
class StringFormatter extends FormatterBase {
class StringFormatter extends FormatterBase implements ContainerFactoryPluginInterface {
/**
* Constructs a StringFormatter instance.
*
* @param string $plugin_id
* The plugin_id for the formatter.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* The definition of the field to which the formatter is associated.
* @param array $settings
* The formatter settings.
* @param string $label
* The formatter label display setting.
* @param string $view_mode
* The view mode.
* @param array $third_party_settings
* Any third party settings settings.
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
*/
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, EntityManagerInterface $entity_manager) {
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
$this->entityManager = $entity_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$plugin_id,
$plugin_definition,
$configuration['field_definition'],
$configuration['settings'],
$configuration['label'],
$configuration['view_mode'],
$configuration['third_party_settings'],
$container->get('entity.manager')
);
}
/**
* {@inheritdoc}
*/
public static function defaultSettings() {
$options = parent::defaultSettings();
$options['link_to_entity'] = FALSE;
return $options;
}
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
$form = parent::settingsForm($form, $form_state);
$entity_type = $this->entityManager->getDefinition($this->fieldDefinition->getTargetEntityTypeId());
$form['link_to_entity'] = [
'#type' => 'checkbox',
'#title' => $this->t('Link to the @entity_label', ['@entity_label' => $entity_type->getLabel()]),
'#default_value' => $this->getSetting('link_to_entity'),
];
return $form;
}
/**
* {@inheritdoc}
*/
public function settingsSummary() {
$build = [];
if ($this->getSetting('link_to_entity')) {
$entity_type = $this->entityManager->getDefinition($this->fieldDefinition->getTargetEntityTypeId());
$build['#markup'] = $this->t('Linked to the @entity_label', ['@entity_label' => $entity_type->getLabel()]);
}
return $build;
}
/**
* {@inheritdoc}
......@@ -35,10 +118,27 @@ class StringFormatter extends FormatterBase {
public function viewElements(FieldItemListInterface $items) {
$elements = array();
$url = NULL;
// Add support to link to the entity itself.
if ($this->getSetting('link_to_entity') && ($entity = $items->getEntity()) && $entity->hasLinkTemplate('canonical')) {
$url = $entity->urlInfo();
}
foreach ($items as $delta => $item) {
// The text value has no text format assigned to it, so the user input
// should equal the output, including newlines.
$elements[$delta] = array('#markup' => nl2br(String::checkPlain($item->value)));
$string = nl2br(String::checkPlain($item->value));
if ($url) {
$elements[$delta] = [
'#type' => 'link',
'#title' => $string,
'#url' => $url,
];
}
else {
$elements[$delta] = ['#markup' => $string];
}
}
return $elements;
......
......@@ -22,7 +22,7 @@
* label = @Translation("Email"),
* description = @Translation("An entity field containing an email value."),
* default_widget = "email_default",
* default_formatter = "string"
* default_formatter = "basic_string"
* )
*/
class EmailItem extends FieldItemBase {
......
......@@ -19,7 +19,7 @@
* label = @Translation("Text (plain, long)"),
* description = @Translation("A field containing a long string value."),
* default_widget = "string_textarea",
* default_formatter = "string",
* default_formatter = "basic_string",
* )
*/
class StringLongItem extends StringItemBase {
......
<?php
/**
* @file
* Contains \Drupal\field\Tests\String\RawStringFormatterTest.
*/
namespace Drupal\field\Tests\String;
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\simpletest\KernelTestBase;
/**
* Tests the raw string formatter
*
* @group field
*/
class RawStringFormatterTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('field', 'text', 'entity_test', 'system', 'filter', 'user');
/**
* @var string
*/
protected $entityType;
/**
* @var string
*/
protected $bundle;
/**
* @var string
*/
protected $fieldName;
/**
* @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface
*/
protected $display;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Configure the theme system.
$this->installConfig(array('system', 'field'));
$this->installSchema('system', 'router');
\Drupal::service('router.builder')->rebuild();
$this->installEntitySchema('entity_test');
$this->entityType = 'entity_test';
$this->bundle = $this->entityType;
$this->fieldName = Unicode::strtolower($this->randomMachineName());
$field_storage = FieldStorageConfig::create(array(
'field_name' => $this->fieldName,
'entity_type' => $this->entityType,
'type' => 'string_long',
));
$field_storage->save();
$instance = FieldConfig::create(array(
'field_storage' => $field_storage,
'bundle' => $this->bundle,
'label' => $this->randomMachineName(),
));
$instance->save();
$this->display = entity_get_display($this->entityType, $this->bundle, 'default')
->setComponent($this->fieldName, array(
'type' => 'string',
'settings' => array(),
));
$this->display->save();
}
/**
* Renders fields of a given entity with a given display.
*
* @param \Drupal\Core\Entity\FieldableEntityInterface $entity
* The entity object with attached fields to render.
* @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
* The display to render the fields in.
*
* @return string
* The rendered entity fields.
*/
protected function renderEntityFields(FieldableEntityInterface $entity, EntityViewDisplayInterface $display) {
$content = $display->build($entity);
$content = $this->render($content);
return $content;
}
/**
* Tests string formatter output.
*/
public function testStringFormatter() {
$value = $this->randomString();
$value .= "\n\n<strong>" . $this->randomString() . '</strong>';
$value .= "\n\n" . $this->randomString();
$entity = EntityTest::create(array());
$entity->{$this->fieldName}->value = $value;
// Verify that all HTML is escaped and newlines are retained.
$this->renderEntityFields($entity, $this->display);
$this->assertNoRaw($value);
$this->assertRaw(nl2br(String::checkPlain($value)));
// Verify the cache tags.
$build = $entity->{$this->fieldName}->view();
$this->assertTrue(!isset($build[0]['#cache']), format_string('The string formatter has no cache tags.'));
}
}
......@@ -58,6 +58,8 @@ protected function setUp() {
// Configure the theme system.
$this->installConfig(array('system', 'field'));
$this->installSchema('system', 'router');
\Drupal::service('router.builder')->rebuild();
$this->installEntitySchema('entity_test');
$this->entityType = 'entity_test';
......@@ -122,6 +124,23 @@ public function testStringFormatter() {
// Verify the cache tags.
$build = $entity->{$this->fieldName}->view();
$this->assertTrue(!isset($build[0]['#cache']), format_string('The string formatter has no cache tags.'));
// Set the formatter to link to the entity.
$this->display->setComponent($this->fieldName, [
'type' => 'string',
'settings' => [
'link_to_entity' => TRUE,
],
]);
$this->display->save();
$value = $this->randomMachineName();
$entity->{$this->fieldName}->value = $value;
$entity->save();
$this->renderEntityFields($entity, $this->display);
$this->assertLink($value, 0);
$this->assertLinkByHref($entity->url());
}
}
......@@ -69,7 +69,9 @@ public function testEntityDisplayCRUD() {
'label' => 'hidden',
'type' => 'string',
'weight' => -5,
'settings' => array(),
'settings' => array(
'link_to_entity' => FALSE,
),
'third_party_settings' => array(),
);
$this->assertEqual($display->getComponents(), $expected);
......
......@@ -54,7 +54,7 @@ process:
text:
default: text_default
trimmed: text_trimmed
plain: string
plain: basic_string
number_integer:
default: number_integer
us_3: number_integer
......@@ -89,7 +89,7 @@ process:
default: email_mailto
spamspan: email_mailto
contact: email_mailto
plain: string
plain: basic_string
link:
default: link
plain: link
......@@ -107,69 +107,69 @@ process:
image_nodelink: image
image_imagelink: image
fr_phone:
default: string
default: basic_string
be_phone:
default: string
default: basic_string
it_phone:
default: string
default: basic_string
el_phone:
default: string
default: basic_string
ch_phone:
default: string
default: basic_string
ca_phone:
default: string
default: basic_string
cr_phone:
default: string
default: basic_string
pa_phone:
default: string
default: basic_string
gb_phone:
default: string
default: basic_string
ru_phone:
default: string
default: basic_string
ua_phone:
default: string
default: basic_string
es_phone:
default: string
default: basic_string
au_phone:
default: string
default: basic_string
cs_phone:
default: string
default: basic_string
hu_phone:
default: string
default: basic_string
pl_phone:
default: string
default: basic_string
nl_phone:
default: string
default: basic_string
se_phone:
default: string
default: basic_string
za_phone:
default: string
default: basic_string
il_phone:
default: string
default: basic_string
nz_phone:
default: string
default: basic_string
br_phone:
default: string
default: basic_string
cl_phone:
default: string
default: basic_string
cn_phone:
default: string
default: basic_string
hk_phone:
default: string
default: basic_string
mo_phone:
default: string
default: basic_string
ph_phone:
default: string
default: basic_string
sg_phone:
default: string
default: basic_string
jo_phone:
default: string
default: basic_string
eg_phone:
default: string
default: basic_string
pk_phone:
default: string
default: basic_string
int_phone:
default: string
default: basic_string
-
plugin: field_type_defaults
"options/settings":
......@@ -306,6 +306,9 @@ process:
text:
trimmed:
trim_length: 600
string:
default:
link_to_entity: false
-
plugin: field_formatter_settings_defaults
"options/third_party_settings": 'constants/third_party_settings'
......
......@@ -177,7 +177,7 @@ public function testEntityDisplaySettings() {
// Test phone field.
$expected['weight'] = 9;
$expected['type'] = 'string';
$expected['type'] = 'basic_string';
$expected['settings'] = array();
$component = $display->getComponent('field_test_phone');
$this->assertEqual($component, $expected, "node.story.teaser field_test_phone is of type telephone.");
......
......@@ -140,6 +140,16 @@ protected function parse() {
return $this->elements;
}
/**
* Get the current URL from the cURL handler.
*
* @return string
* The current URL.
*/
protected function getUrl() {
return isset($this->url) ? $this->url : 'no-url';
}
/**
* Builds an XPath query.
*
......
......@@ -2307,16 +2307,6 @@ protected function getAbsoluteUrl($path) {
return $path;
}
/**
* Get the current URL from the cURL handler.
*
* @return
* The current URL.
*/
protected function getUrl() {
return $this->url;
}
/**
* Gets the HTTP response headers of the requested page.
*
......
......@@ -20,7 +20,7 @@
* label = @Translation("Telephone number"),
* description = @Translation("This field stores a telephone number in the database."),
* default_widget = "telephone_default",
* default_formatter = "string"
* default_formatter = "basic_string"
* )
*/
class TelephoneItem extends FieldItemBase {
......
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