View source
<?php
namespace Drupal\views\Plugin\views\field;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\MarkupInterface;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Renderer;
use Drupal\Core\Url as CoreUrl;
use Drupal\views\Plugin\views\HandlerBase;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\views\Render\ViewsRenderPipelineMarkup;
use Drupal\views\ResultRow;
use Drupal\views\ViewExecutable;
abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterface {
const RENDER_TEXT_PHASE_SINGLE_ITEM = 0;
const RENDER_TEXT_PHASE_COMPLETELY = 1;
const RENDER_TEXT_PHASE_EMPTY = 2;
var $field_alias = 'unknown';
var $aliases = array();
public $original_value = NULL;
var $additional_fields = array();
protected $linkGenerator;
protected $renderer;
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
parent::init($view, $display, $options);
$this->additional_fields = array();
if (!empty($this->definition['additional fields'])) {
$this->additional_fields = $this->definition['additional fields'];
}
if (!isset($this->options['exclude'])) {
$this->options['exclude'] = '';
}
}
protected function allowAdvancedRender() {
return TRUE;
}
public function query() {
$this
->ensureMyTable();
$params = $this->options['group_type'] != 'group' ? array(
'function' => $this->options['group_type'],
) : array();
$this->field_alias = $this->query
->addField($this->tableAlias, $this->realField, NULL, $params);
$this
->addAdditionalFields();
}
protected function addAdditionalFields($fields = NULL) {
if (!isset($fields)) {
if (empty($this->additional_fields)) {
return;
}
$fields = $this->additional_fields;
}
$group_params = array();
if ($this->options['group_type'] != 'group') {
$group_params = array(
'function' => $this->options['group_type'],
);
}
if (!empty($fields) && is_array($fields)) {
foreach ($fields as $identifier => $info) {
if (is_array($info)) {
if (isset($info['table'])) {
$table_alias = $this->query
->ensureTable($info['table'], $this->relationship);
}
else {
$table_alias = $this->tableAlias;
}
if (empty($table_alias)) {
debug(t('Handler @handler tried to add additional_field @identifier but @table could not be added!', array(
'@handler' => $this->definition['id'],
'@identifier' => $identifier,
'@table' => $info['table'],
)));
$this->aliases[$identifier] = 'broken';
continue;
}
$params = array();
if (!empty($info['params'])) {
$params = $info['params'];
}
$params += $group_params;
$this->aliases[$identifier] = $this->query
->addField($table_alias, $info['field'], NULL, $params);
}
else {
$this->aliases[$info] = $this->query
->addField($this->tableAlias, $info, NULL, $group_params);
}
}
}
}
public function clickSort($order) {
if (isset($this->field_alias)) {
$params = $this->options['group_type'] != 'group' ? array(
'function' => $this->options['group_type'],
) : array();
$this->query
->addOrderBy(NULL, NULL, $order, $this->field_alias, $params);
}
}
public function clickSortable() {
return isset($this->definition['click sortable']) ? $this->definition['click sortable'] : TRUE;
}
public function label() {
if (!isset($this->options['label'])) {
return '';
}
return $this->options['label'];
}
public function elementType($none_supported = FALSE, $default_empty = FALSE, $inline = FALSE) {
if ($none_supported) {
if ($this->options['element_type'] === '0') {
return '';
}
}
if ($this->options['element_type']) {
return $this->options['element_type'];
}
if ($default_empty) {
return '';
}
if ($inline) {
return 'span';
}
if (isset($this->definition['element type'])) {
return $this->definition['element type'];
}
return 'span';
}
public function elementLabelType($none_supported = FALSE, $default_empty = FALSE) {
if ($none_supported) {
if ($this->options['element_label_type'] === '0') {
return '';
}
}
if ($this->options['element_label_type']) {
return $this->options['element_label_type'];
}
if ($default_empty) {
return '';
}
return 'span';
}
public function elementWrapperType($none_supported = FALSE, $default_empty = FALSE) {
if ($none_supported) {
if ($this->options['element_wrapper_type'] === '0') {
return 0;
}
}
if ($this->options['element_wrapper_type']) {
return $this->options['element_wrapper_type'];
}
if ($default_empty) {
return '';
}
return 'div';
}
public function getElements() {
static $elements = NULL;
if (!isset($elements)) {
$elements = array(
'' => $this
->t(' - Use default -'),
'0' => $this
->t('- None -'),
);
$elements += \Drupal::config('views.settings')
->get('field_rewrite_elements');
}
return $elements;
}
public function elementClasses($row_index = NULL) {
$classes = explode(' ', $this->options['element_class']);
foreach ($classes as &$class) {
$class = $this
->tokenizeValue($class, $row_index);
$class = Html::cleanCssIdentifier($class);
}
return implode(' ', $classes);
}
public function tokenizeValue($value, $row_index = NULL) {
if (strpos($value, '{{') !== FALSE) {
$fake_item = array(
'alter_text' => TRUE,
'text' => $value,
);
if (isset($row_index) && isset($this->view->style_plugin->render_tokens[$row_index])) {
$tokens = $this->view->style_plugin->render_tokens[$row_index];
}
else {
$last_field = end($this->view->field);
if (isset($last_field->last_tokens)) {
$tokens = $last_field->last_tokens;
}
else {
$tokens = $last_field
->getRenderTokens($fake_item);
}
}
$value = strip_tags($this
->renderAltered($fake_item, $tokens));
if (!empty($this->options['alter']['trim_whitespace'])) {
$value = trim($value);
}
}
return $value;
}
public function elementLabelClasses($row_index = NULL) {
$classes = explode(' ', $this->options['element_label_class']);
foreach ($classes as &$class) {
$class = $this
->tokenizeValue($class, $row_index);
$class = Html::cleanCssIdentifier($class);
}
return implode(' ', $classes);
}
public function elementWrapperClasses($row_index = NULL) {
$classes = explode(' ', $this->options['element_wrapper_class']);
foreach ($classes as &$class) {
$class = $this
->tokenizeValue($class, $row_index);
$class = Html::cleanCssIdentifier($class);
}
return implode(' ', $classes);
}
public function getEntity(ResultRow $values) {
$relationship_id = $this->options['relationship'];
if ($relationship_id == 'none') {
return $values->_entity;
}
elseif (isset($values->_relationship_entities[$relationship_id])) {
return $values->_relationship_entities[$relationship_id];
}
}
public function getValue(ResultRow $values, $field = NULL) {
$alias = isset($field) ? $this->aliases[$field] : $this->field_alias;
if (isset($values->{$alias})) {
return $values->{$alias};
}
}
public function useStringGroupBy() {
return TRUE;
}
protected function defineOptions() {
$options = parent::defineOptions();
$options['label'] = array(
'default' => '',
);
$style = $this->view
->getStyle();
if (isset($style) && $style
->defaultFieldLabels()) {
$options['label']['default'] = $this->definition['title'];
}
$options['exclude'] = array(
'default' => FALSE,
);
$options['alter'] = array(
'contains' => array(
'alter_text' => array(
'default' => FALSE,
),
'text' => array(
'default' => '',
),
'make_link' => array(
'default' => FALSE,
),
'path' => array(
'default' => '',
),
'absolute' => array(
'default' => FALSE,
),
'external' => array(
'default' => FALSE,
),
'replace_spaces' => array(
'default' => FALSE,
),
'path_case' => array(
'default' => 'none',
),
'trim_whitespace' => array(
'default' => FALSE,
),
'alt' => array(
'default' => '',
),
'rel' => array(
'default' => '',
),
'link_class' => array(
'default' => '',
),
'prefix' => array(
'default' => '',
),
'suffix' => array(
'default' => '',
),
'target' => array(
'default' => '',
),
'nl2br' => array(
'default' => FALSE,
),
'max_length' => array(
'default' => 0,
),
'word_boundary' => array(
'default' => TRUE,
),
'ellipsis' => array(
'default' => TRUE,
),
'more_link' => array(
'default' => FALSE,
),
'more_link_text' => array(
'default' => '',
),
'more_link_path' => array(
'default' => '',
),
'strip_tags' => array(
'default' => FALSE,
),
'trim' => array(
'default' => FALSE,
),
'preserve_tags' => array(
'default' => '',
),
'html' => array(
'default' => FALSE,
),
),
);
$options['element_type'] = array(
'default' => '',
);
$options['element_class'] = array(
'default' => '',
);
$options['element_label_type'] = array(
'default' => '',
);
$options['element_label_class'] = array(
'default' => '',
);
$options['element_label_colon'] = array(
'default' => TRUE,
);
$options['element_wrapper_type'] = array(
'default' => '',
);
$options['element_wrapper_class'] = array(
'default' => '',
);
$options['element_default_classes'] = array(
'default' => TRUE,
);
$options['empty'] = array(
'default' => '',
);
$options['hide_empty'] = array(
'default' => FALSE,
);
$options['empty_zero'] = array(
'default' => FALSE,
);
$options['hide_alter_empty'] = array(
'default' => TRUE,
);
return $options;
}
public function submitOptionsForm(&$form, FormStateInterface $form_state) {
$options =& $form_state
->getValue('options');
$types = array(
'element_type',
'element_label_type',
'element_wrapper_type',
);
$classes = array_combine(array(
'element_class',
'element_label_class',
'element_wrapper_class',
), $types);
foreach ($types as $type) {
if (!$options[$type . '_enable']) {
$options[$type] = '';
}
}
foreach ($classes as $class => $type) {
if (!$options[$class . '_enable'] || !$options[$type . '_enable']) {
$options[$class] = '';
}
}
if (empty($options['custom_label'])) {
$options['label'] = '';
$options['element_label_colon'] = FALSE;
}
}
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
$label = $this
->label();
$form['custom_label'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Create a label'),
'#default_value' => $label !== '',
'#weight' => -103,
);
$form['label'] = array(
'#type' => 'textfield',
'#title' => $this
->t('Label'),
'#default_value' => $label,
'#states' => array(
'visible' => array(
':input[name="options[custom_label]"]' => array(
'checked' => TRUE,
),
),
),
'#weight' => -102,
);
$form['element_label_colon'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Place a colon after the label'),
'#default_value' => $this->options['element_label_colon'],
'#states' => array(
'visible' => array(
':input[name="options[custom_label]"]' => array(
'checked' => TRUE,
),
),
),
'#weight' => -101,
);
$form['exclude'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Exclude from display'),
'#default_value' => $this->options['exclude'],
'#description' => $this
->t('Enable to load this field as hidden. Often used to group fields, or to use as token in another field.'),
'#weight' => -100,
);
$form['style_settings'] = array(
'#type' => 'details',
'#title' => $this
->t('Style settings'),
'#weight' => 99,
);
$form['element_type_enable'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Customize field HTML'),
'#default_value' => !empty($this->options['element_type']) || (string) $this->options['element_type'] == '0' || !empty($this->options['element_class']) || (string) $this->options['element_class'] == '0',
'#fieldset' => 'style_settings',
);
$form['element_type'] = array(
'#title' => $this
->t('HTML element'),
'#options' => $this
->getElements(),
'#type' => 'select',
'#default_value' => $this->options['element_type'],
'#description' => $this
->t('Choose the HTML element to wrap around this field, e.g. H1, H2, etc.'),
'#states' => array(
'visible' => array(
':input[name="options[element_type_enable]"]' => array(
'checked' => TRUE,
),
),
),
'#fieldset' => 'style_settings',
);
$form['element_class_enable'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Create a CSS class'),
'#states' => array(
'visible' => array(
':input[name="options[element_type_enable]"]' => array(
'checked' => TRUE,
),
),
),
'#default_value' => !empty($this->options['element_class']) || (string) $this->options['element_class'] == '0',
'#fieldset' => 'style_settings',
);
$form['element_class'] = array(
'#title' => $this
->t('CSS class'),
'#description' => $this
->t('You may use token substitutions from the rewriting section in this class.'),
'#type' => 'textfield',
'#default_value' => $this->options['element_class'],
'#states' => array(
'visible' => array(
':input[name="options[element_type_enable]"]' => array(
'checked' => TRUE,
),
':input[name="options[element_class_enable]"]' => array(
'checked' => TRUE,
),
),
),
'#fieldset' => 'style_settings',
);
$form['element_label_type_enable'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Customize label HTML'),
'#default_value' => !empty($this->options['element_label_type']) || (string) $this->options['element_label_type'] == '0' || !empty($this->options['element_label_class']) || (string) $this->options['element_label_class'] == '0',
'#fieldset' => 'style_settings',
);
$form['element_label_type'] = array(
'#title' => $this
->t('Label HTML element'),
'#options' => $this
->getElements(FALSE),
'#type' => 'select',
'#default_value' => $this->options['element_label_type'],
'#description' => $this
->t('Choose the HTML element to wrap around this label, e.g. H1, H2, etc.'),
'#states' => array(
'visible' => array(
':input[name="options[element_label_type_enable]"]' => array(
'checked' => TRUE,
),
),
),
'#fieldset' => 'style_settings',
);
$form['element_label_class_enable'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Create a CSS class'),
'#states' => array(
'visible' => array(
':input[name="options[element_label_type_enable]"]' => array(
'checked' => TRUE,
),
),
),
'#default_value' => !empty($this->options['element_label_class']) || (string) $this->options['element_label_class'] == '0',
'#fieldset' => 'style_settings',
);
$form['element_label_class'] = array(
'#title' => $this
->t('CSS class'),
'#description' => $this
->t('You may use token substitutions from the rewriting section in this class.'),
'#type' => 'textfield',
'#default_value' => $this->options['element_label_class'],
'#states' => array(
'visible' => array(
':input[name="options[element_label_type_enable]"]' => array(
'checked' => TRUE,
),
':input[name="options[element_label_class_enable]"]' => array(
'checked' => TRUE,
),
),
),
'#fieldset' => 'style_settings',
);
$form['element_wrapper_type_enable'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Customize field and label wrapper HTML'),
'#default_value' => !empty($this->options['element_wrapper_type']) || (string) $this->options['element_wrapper_type'] == '0' || !empty($this->options['element_wrapper_class']) || (string) $this->options['element_wrapper_class'] == '0',
'#fieldset' => 'style_settings',
);
$form['element_wrapper_type'] = array(
'#title' => $this
->t('Wrapper HTML element'),
'#options' => $this
->getElements(FALSE),
'#type' => 'select',
'#default_value' => $this->options['element_wrapper_type'],
'#description' => $this
->t('Choose the HTML element to wrap around this field and label, e.g. H1, H2, etc. This may not be used if the field and label are not rendered together, such as with a table.'),
'#states' => array(
'visible' => array(
':input[name="options[element_wrapper_type_enable]"]' => array(
'checked' => TRUE,
),
),
),
'#fieldset' => 'style_settings',
);
$form['element_wrapper_class_enable'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Create a CSS class'),
'#states' => array(
'visible' => array(
':input[name="options[element_wrapper_type_enable]"]' => array(
'checked' => TRUE,
),
),
),
'#default_value' => !empty($this->options['element_wrapper_class']) || (string) $this->options['element_wrapper_class'] == '0',
'#fieldset' => 'style_settings',
);
$form['element_wrapper_class'] = array(
'#title' => $this
->t('CSS class'),
'#description' => $this
->t('You may use token substitutions from the rewriting section in this class.'),
'#type' => 'textfield',
'#default_value' => $this->options['element_wrapper_class'],
'#states' => array(
'visible' => array(
':input[name="options[element_wrapper_class_enable]"]' => array(
'checked' => TRUE,
),
':input[name="options[element_wrapper_type_enable]"]' => array(
'checked' => TRUE,
),
),
),
'#fieldset' => 'style_settings',
);
$form['element_default_classes'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Add default classes'),
'#default_value' => $this->options['element_default_classes'],
'#description' => $this
->t('Use default Views classes to identify the field, field label and field content.'),
'#fieldset' => 'style_settings',
);
$form['alter'] = array(
'#title' => $this
->t('Rewrite results'),
'#type' => 'details',
'#weight' => 100,
);
if ($this
->allowAdvancedRender()) {
$form['alter']['#tree'] = TRUE;
$form['alter']['alter_text'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Override the output of this field with custom text'),
'#default_value' => $this->options['alter']['alter_text'],
);
$form['alter']['text'] = array(
'#title' => $this
->t('Text'),
'#type' => 'textarea',
'#default_value' => $this->options['alter']['text'],
'#description' => $this
->t('The text to display for this field. You may include HTML or <a href=":url">Twig</a>. You may enter data from this view as per the "Replacement patterns" below.', array(
':url' => CoreUrl::fromUri('http://twig.sensiolabs.org/documentation')
->toString(),
)),
'#states' => array(
'visible' => array(
':input[name="options[alter][alter_text]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['alter']['make_link'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Output this field as a custom link'),
'#default_value' => $this->options['alter']['make_link'],
);
$form['alter']['path'] = array(
'#title' => $this
->t('Link path'),
'#type' => 'textfield',
'#default_value' => $this->options['alter']['path'],
'#description' => $this
->t('The Drupal path or absolute URL for this link. You may enter data from this view as per the "Replacement patterns" below.'),
'#states' => array(
'visible' => array(
':input[name="options[alter][make_link]"]' => array(
'checked' => TRUE,
),
),
),
'#maxlength' => 255,
);
$form['alter']['absolute'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Use absolute path'),
'#default_value' => $this->options['alter']['absolute'],
'#states' => array(
'visible' => array(
':input[name="options[alter][make_link]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['alter']['replace_spaces'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Replace spaces with dashes'),
'#default_value' => $this->options['alter']['replace_spaces'],
'#states' => array(
'visible' => array(
':input[name="options[alter][make_link]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['alter']['external'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('External server URL'),
'#default_value' => $this->options['alter']['external'],
'#description' => $this
->t("Links to an external server using a full URL: e.g. 'http://www.example.com' or 'www.example.com'."),
'#states' => array(
'visible' => array(
':input[name="options[alter][make_link]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['alter']['path_case'] = array(
'#type' => 'select',
'#title' => $this
->t('Transform the case'),
'#description' => $this
->t('When printing url paths, how to transform the case of the filter value.'),
'#states' => array(
'visible' => array(
':input[name="options[alter][make_link]"]' => array(
'checked' => TRUE,
),
),
),
'#options' => array(
'none' => $this
->t('No transform'),
'upper' => $this
->t('Upper case'),
'lower' => $this
->t('Lower case'),
'ucfirst' => $this
->t('Capitalize first letter'),
'ucwords' => $this
->t('Capitalize each word'),
),
'#default_value' => $this->options['alter']['path_case'],
);
$form['alter']['link_class'] = array(
'#title' => $this
->t('Link class'),
'#type' => 'textfield',
'#default_value' => $this->options['alter']['link_class'],
'#description' => $this
->t('The CSS class to apply to the link.'),
'#states' => array(
'visible' => array(
':input[name="options[alter][make_link]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['alter']['alt'] = array(
'#title' => $this
->t('Title text'),
'#type' => 'textfield',
'#default_value' => $this->options['alter']['alt'],
'#description' => $this
->t('Text to place as "title" text which most browsers display as a tooltip when hovering over the link.'),
'#states' => array(
'visible' => array(
':input[name="options[alter][make_link]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['alter']['rel'] = array(
'#title' => $this
->t('Rel Text'),
'#type' => 'textfield',
'#default_value' => $this->options['alter']['rel'],
'#description' => $this
->t('Include Rel attribute for use in lightbox2 or other javascript utility.'),
'#states' => array(
'visible' => array(
':input[name="options[alter][make_link]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['alter']['prefix'] = array(
'#title' => $this
->t('Prefix text'),
'#type' => 'textfield',
'#default_value' => $this->options['alter']['prefix'],
'#description' => $this
->t('Any text to display before this link. You may include HTML.'),
'#states' => array(
'visible' => array(
':input[name="options[alter][make_link]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['alter']['suffix'] = array(
'#title' => $this
->t('Suffix text'),
'#type' => 'textfield',
'#default_value' => $this->options['alter']['suffix'],
'#description' => $this
->t('Any text to display after this link. You may include HTML.'),
'#states' => array(
'visible' => array(
':input[name="options[alter][make_link]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['alter']['target'] = array(
'#title' => $this
->t('Target'),
'#type' => 'textfield',
'#default_value' => $this->options['alter']['target'],
'#description' => $this
->t("Target of the link, such as _blank, _parent or an iframe's name. This field is rarely used."),
'#states' => array(
'visible' => array(
':input[name="options[alter][make_link]"]' => array(
'checked' => TRUE,
),
),
),
);
$previous = $this
->getPreviousFieldLabels();
$optgroup_arguments = (string) t('Arguments');
$optgroup_fields = (string) t('Fields');
foreach ($previous as $id => $label) {
$options[$optgroup_fields]["{{ {$id} }}"] = substr(strrchr($label, ":"), 2);
}
$options[$optgroup_fields]["{{ {$this->options['id']} }}"] = substr(strrchr($this
->adminLabel(), ":"), 2);
foreach ($this->view->display_handler
->getHandlers('argument') as $arg => $handler) {
$options[$optgroup_arguments]["{{ arguments.{$arg} }}"] = $this
->t('@argument title', array(
'@argument' => $handler
->adminLabel(),
));
$options[$optgroup_arguments]["{{ raw_arguments.{$arg} }}"] = $this
->t('@argument input', array(
'@argument' => $handler
->adminLabel(),
));
}
$this
->documentSelfTokens($options[$optgroup_fields]);
$output = [];
$output[] = [
'#markup' => '<p>' . $this
->t('You must add some additional fields to this display before using this field. These fields may be marked as <em>Exclude from display</em> if you prefer. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.') . '</p>',
];
if (!empty($options)) {
$output[] = [
'#markup' => '<p>' . $this
->t("The following replacement tokens are available for this field. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.") . '</p>',
];
foreach (array_keys($options) as $type) {
if (!empty($options[$type])) {
$items = array();
foreach ($options[$type] as $key => $value) {
$items[] = $key . ' == ' . $value;
}
$item_list = array(
'#theme' => 'item_list',
'#items' => $items,
);
$output[] = $item_list;
}
}
}
$form['alter']['help'] = array(
'#type' => 'details',
'#title' => $this
->t('Replacement patterns'),
'#value' => $output,
'#states' => array(
'visible' => array(
array(
':input[name="options[alter][make_link]"]' => array(
'checked' => TRUE,
),
),
array(
':input[name="options[alter][alter_text]"]' => array(
'checked' => TRUE,
),
),
array(
':input[name="options[alter][more_link]"]' => array(
'checked' => TRUE,
),
),
),
),
);
$form['alter']['trim'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Trim this field to a maximum number of characters'),
'#default_value' => $this->options['alter']['trim'],
);
$form['alter']['max_length'] = array(
'#title' => $this
->t('Maximum number of characters'),
'#type' => 'textfield',
'#default_value' => $this->options['alter']['max_length'],
'#states' => array(
'visible' => array(
':input[name="options[alter][trim]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['alter']['word_boundary'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Trim only on a word boundary'),
'#description' => $this
->t('If checked, this field be trimmed only on a word boundary. This is guaranteed to be the maximum characters stated or less. If there are no word boundaries this could trim a field to nothing.'),
'#default_value' => $this->options['alter']['word_boundary'],
'#states' => array(
'visible' => array(
':input[name="options[alter][trim]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['alter']['ellipsis'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Add "…" at the end of trimmed text'),
'#default_value' => $this->options['alter']['ellipsis'],
'#states' => array(
'visible' => array(
':input[name="options[alter][trim]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['alter']['more_link'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Add a read-more link if output is trimmed'),
'#default_value' => $this->options['alter']['more_link'],
'#states' => array(
'visible' => array(
':input[name="options[alter][trim]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['alter']['more_link_text'] = array(
'#type' => 'textfield',
'#title' => $this
->t('More link label'),
'#default_value' => $this->options['alter']['more_link_text'],
'#description' => $this
->t('You may use the "Replacement patterns" above.'),
'#states' => array(
'visible' => array(
':input[name="options[alter][trim]"]' => array(
'checked' => TRUE,
),
':input[name="options[alter][more_link]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['alter']['more_link_path'] = array(
'#type' => 'textfield',
'#title' => $this
->t('More link path'),
'#default_value' => $this->options['alter']['more_link_path'],
'#description' => $this
->t('This can be an internal Drupal path such as node/add or an external URL such as "https://www.drupal.org". You may use the "Replacement patterns" above.'),
'#states' => array(
'visible' => array(
':input[name="options[alter][trim]"]' => array(
'checked' => TRUE,
),
':input[name="options[alter][more_link]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['alter']['html'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Field can contain HTML'),
'#description' => $this
->t('An HTML corrector will be run to ensure HTML tags are properly closed after trimming.'),
'#default_value' => $this->options['alter']['html'],
'#states' => array(
'visible' => array(
':input[name="options[alter][trim]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['alter']['strip_tags'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Strip HTML tags'),
'#default_value' => $this->options['alter']['strip_tags'],
);
$form['alter']['preserve_tags'] = array(
'#type' => 'textfield',
'#title' => $this
->t('Preserve certain tags'),
'#description' => $this
->t('List the tags that need to be preserved during the stripping process. example "<p> <br>" which will preserve all p and br elements'),
'#default_value' => $this->options['alter']['preserve_tags'],
'#states' => array(
'visible' => array(
':input[name="options[alter][strip_tags]"]' => array(
'checked' => TRUE,
),
),
),
);
$form['alter']['trim_whitespace'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Remove whitespace'),
'#default_value' => $this->options['alter']['trim_whitespace'],
);
$form['alter']['nl2br'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Convert newlines to HTML <br> tags'),
'#default_value' => $this->options['alter']['nl2br'],
);
}
$form['empty_field_behavior'] = array(
'#type' => 'details',
'#title' => $this
->t('No results behavior'),
'#weight' => 100,
);
$form['empty'] = array(
'#type' => 'textarea',
'#title' => $this
->t('No results text'),
'#default_value' => $this->options['empty'],
'#description' => $this
->t('Provide text to display if this field contains an empty result. You may include HTML. You may enter data from this view as per the "Replacement patterns" in the "Rewrite Results" section below.'),
'#fieldset' => 'empty_field_behavior',
);
$form['empty_zero'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Count the number 0 as empty'),
'#default_value' => $this->options['empty_zero'],
'#description' => $this
->t('Enable to display the "no results text" if the field contains the number 0.'),
'#fieldset' => 'empty_field_behavior',
);
$form['hide_empty'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Hide if empty'),
'#default_value' => $this->options['hide_empty'],
'#description' => $this
->t('Enable to hide this field if it is empty. Note that the field label or rewritten output may still be displayed. To hide labels, check the style or row style settings for empty fields. To hide rewritten content, check the "Hide rewriting if empty" checkbox.'),
'#fieldset' => 'empty_field_behavior',
);
$form['hide_alter_empty'] = array(
'#type' => 'checkbox',
'#title' => $this
->t('Hide rewriting if empty'),
'#default_value' => $this->options['hide_alter_empty'],
'#description' => $this
->t('Do not display rewritten content if this field is empty.'),
'#fieldset' => 'empty_field_behavior',
);
}
protected function getPreviousFieldLabels() {
$all_fields = $this->view->display_handler
->getFieldLabels();
$field_options = array_slice($all_fields, 0, array_search($this->options['id'], array_keys($all_fields)));
return $field_options;
}
public function adminSummary() {
return $this
->label();
}
public function preRender(&$values) {
}
public function render(ResultRow $values) {
$value = $this
->getValue($values);
return $this
->sanitizeValue($value);
}
public function postRender(ResultRow $row, $output) {
$this->last_render = $output;
return [];
}
public function advancedRender(ResultRow $values) {
if ($this
->allowAdvancedRender() && $this instanceof MultiItemsFieldHandlerInterface) {
$raw_items = $this
->getItems($values);
if (empty($raw_items)) {
$this->original_value = NULL;
}
}
else {
$value = $this
->render($values);
if (is_array($value)) {
$value = $this
->getRenderer()
->render($value);
}
$this->last_render = $value;
$this->original_value = $value;
}
if ($this
->allowAdvancedRender()) {
$tokens = NULL;
if ($this instanceof MultiItemsFieldHandlerInterface) {
$items = array();
foreach ($raw_items as $count => $item) {
$value = $this
->render_item($count, $item);
if (is_array($value)) {
$value = (string) $this
->getRenderer()
->render($value);
}
$this->last_render = $value;
$this->original_value = $this->last_render;
$alter = $item + $this->options['alter'];
$alter['phase'] = static::RENDER_TEXT_PHASE_SINGLE_ITEM;
$items[] = $this
->renderText($alter);
}
$value = $this
->renderItems($items);
}
else {
$alter = array(
'phase' => static::RENDER_TEXT_PHASE_COMPLETELY,
) + $this->options['alter'];
$value = $this
->renderText($alter);
}
if (is_array($value)) {
$value = $this
->getRenderer()
->render($value);
}
$this->last_render = $value;
}
if (empty((string) $this->last_render)) {
if ($this
->isValueEmpty($this->last_render, $this->options['empty_zero'], FALSE)) {
$alter = $this->options['alter'];
$alter['alter_text'] = 1;
$alter['text'] = $this->options['empty'];
$alter['phase'] = static::RENDER_TEXT_PHASE_EMPTY;
$this->last_render = $this
->renderText($alter);
}
}
return $this->last_render;
}
public function isValueEmpty($value, $empty_zero, $no_skip_empty = TRUE) {
if ($value instanceof MarkupInterface) {
$value = (string) $value;
}
if (!isset($value)) {
$empty = TRUE;
}
else {
$empty = $empty_zero || $value !== 0 && $value !== '0';
}
if ($no_skip_empty) {
$empty = empty($value) && $empty;
}
return $empty;
}
public function renderText($alter) {
$value_is_safe = SafeMarkup::isSafe($this->last_render);
$value = (string) $this->last_render;
if (!empty($alter['alter_text']) && $alter['text'] !== '') {
$tokens = $this
->getRenderTokens($alter);
$value = $this
->renderAltered($alter, $tokens);
}
if (!empty($this->options['alter']['trim_whitespace'])) {
$value = trim($value);
}
$no_rewrite_for_empty = $this->options['hide_alter_empty'] && $this
->isValueEmpty($this->original_value, $this->options['empty_zero']);
if (($this->options['hide_empty'] && empty($value) || $alter['phase'] != static::RENDER_TEXT_PHASE_EMPTY && $no_rewrite_for_empty) && $this
->isValueEmpty($value, $this->options['empty_zero'], FALSE)) {
return '';
}
if ($alter['phase'] == static::RENDER_TEXT_PHASE_EMPTY && $no_rewrite_for_empty) {
if ($value_is_safe) {
$value = ViewsRenderPipelineMarkup::create($value);
}
return $value;
}
if (!empty($alter['strip_tags'])) {
$value = strip_tags($value, $alter['preserve_tags']);
}
$more_link = '';
if (!empty($alter['trim']) && !empty($alter['max_length'])) {
$length = strlen($value);
$value = $this
->renderTrimText($alter, $value);
if ($this->options['alter']['more_link'] && strlen($value) < $length) {
$tokens = $this
->getRenderTokens($alter);
$more_link_text = $this->options['alter']['more_link_text'] ? $this->options['alter']['more_link_text'] : $this
->t('more');
$more_link_text = strtr(Xss::filterAdmin($more_link_text), $tokens);
$more_link_path = $this->options['alter']['more_link_path'];
$more_link_path = strip_tags(Html::decodeEntities($this
->viewsTokenReplace($more_link_path, $tokens)));
$base_path = base_path();
if (strpos($more_link_path, $base_path) === 0) {
$more_link_path = Unicode::substr($more_link_path, Unicode::strlen($base_path));
}
$more_link = ' ' . $this
->linkGenerator()
->generate($more_link_text, CoreUrl::fromUserInput('/' . $more_link_path, array(
'attributes' => array(
'class' => array(
'views-more-link',
),
),
)));
}
}
if (!empty($alter['nl2br'])) {
$value = nl2br($value);
}
if ($value_is_safe) {
$value = ViewsRenderPipelineMarkup::create($value);
}
$this->last_render_text = $value;
if (!empty($alter['make_link']) && (!empty($alter['path']) || !empty($alter['url']))) {
if (!isset($tokens)) {
$tokens = $this
->getRenderTokens($alter);
}
$value = $this
->renderAsLink($alter, $value, $tokens);
}
if (SafeMarkup::isSafe($value)) {
return ViewsRenderPipelineMarkup::create($value . $more_link);
}
else {
return $value . $more_link;
}
}
protected function renderAltered($alter, $tokens) {
return $this
->viewsTokenReplace($alter['text'], $tokens);
}
protected function renderTrimText($alter, $value) {
if (!empty($alter['strip_tags'])) {
$this->definition['element type'] = 'span';
}
return static::trimText($alter, $value);
}
protected function renderAsLink($alter, $text, $tokens) {
$options = array(
'absolute' => !empty($alter['absolute']) ? TRUE : FALSE,
'alias' => FALSE,
'entity' => NULL,
'entity_type' => NULL,
'fragment' => NULL,
'language' => NULL,
'query' => [],
);
$alter += [
'path' => NULL,
];
$path = $alter['path'];
if (empty($alter['url'])) {
if (!parse_url($path, PHP_URL_SCHEME)) {
$alter['url'] = CoreUrl::fromUserInput('/' . ltrim($path, '/'));
}
else {
$alter['url'] = CoreUrl::fromUri($path);
}
}
$options = $alter['url']
->getOptions() + $options;
$path = $alter['url']
->setOptions($options)
->toUriString();
if ($path != 'route:<front>') {
$path = preg_replace([
'/(\\%7B){2}(\\%20)*/',
'/(\\%20)*(\\%7D){2}/',
], [
'{{',
'}}',
], $path);
$path = strip_tags(Html::decodeEntities($this
->viewsTokenReplace($path, $tokens)));
if (!empty($alter['path_case']) && $alter['path_case'] != 'none' && !$alter['url']
->isRouted()) {
$path = str_replace($alter['path'], $this
->caseTransform($alter['path'], $this->options['alter']['path_case']), $path);
}
if (!empty($alter['replace_spaces'])) {
$path = str_replace(' ', '-', $path);
}
}
$url = UrlHelper::parse($path);
if (empty($url)) {
return $text;
}
if (empty($url['path']) && empty($url['host']) && empty($url['fragment']) && empty($url['url'])) {
return $text;
}
$path = $url['path'];
if ($alter['external']) {
if (!isset($url['scheme'])) {
$path = "http://" . $alter['path'];
$url = UrlHelper::parse($path);
}
}
if (isset($url['query'])) {
foreach ($url['query'] as $param => $val) {
if ($val == '%' . $param) {
unset($url['query'][$param]);
}
if ($val === '') {
$url['query'][$param] = NULL;
}
}
$options['query'] = $url['query'];
}
if (isset($url['fragment'])) {
$path = strtr($path, array(
'#' . $url['fragment'] => '',
));
if ($path == '') {
$options['external'] = TRUE;
}
$options['fragment'] = $url['fragment'];
}
$alt = $this
->viewsTokenReplace($alter['alt'], $tokens);
if ($alt && $alt != $text) {
$options['attributes']['title'] = Html::decodeEntities($alt);
}
$class = $this
->viewsTokenReplace($alter['link_class'], $tokens);
if ($class) {
$options['attributes']['class'] = array(
$class,
);
}
if (!empty($alter['rel']) && ($rel = $this
->viewsTokenReplace($alter['rel'], $tokens))) {
$options['attributes']['rel'] = $rel;
}
$target = trim($this
->viewsTokenReplace($alter['target'], $tokens));
if (!empty($target)) {
$options['attributes']['target'] = $target;
}
if (isset($alter['link_attributes']) && is_array($alter['link_attributes'])) {
foreach ($alter['link_attributes'] as $key => $attribute) {
if (!isset($options['attributes'][$key])) {
$options['attributes'][$key] = $this
->viewsTokenReplace($attribute, $tokens);
}
}
}
if (isset($alter['query'])) {
$options['query'] = UrlHelper::buildQuery($alter['query']);
$options['query'] = $this
->viewsTokenReplace($options['query'], $tokens);
$query = array();
parse_str($options['query'], $query);
$options['query'] = $query;
}
if (isset($alter['alias'])) {
$options['alias'] = $alter['alias'];
}
if (isset($alter['fragment'])) {
$options['fragment'] = $this
->viewsTokenReplace($alter['fragment'], $tokens);
}
if (isset($alter['language'])) {
$options['language'] = $alter['language'];
}
if (isset($alter['entity'])) {
$options['entity'] = $alter['entity'];
}
if (isset($alter['entity_type'])) {
$options['entity_type'] = $alter['entity_type'];
}
$final_url = CoreUrl::fromUri($path, $options);
$render = [
'#type' => 'link',
'#title' => $text,
'#url' => $final_url,
];
if (!empty($alter['prefix'])) {
$render['#prefix'] = $this
->viewsTokenReplace($alter['prefix'], $tokens);
}
if (!empty($alter['suffix'])) {
$render['#suffix'] = $this
->viewsTokenReplace($alter['suffix'], $tokens);
}
return $this
->getRenderer()
->render($render);
}
public function getRenderTokens($item) {
$tokens = array();
if (!empty($this->view->build_info['substitutions'])) {
$tokens = $this->view->build_info['substitutions'];
}
$count = 0;
foreach ($this->displayHandler
->getHandlers('argument') as $arg => $handler) {
$token = "{{ arguments.{$arg} }}";
if (!isset($tokens[$token])) {
$tokens[$token] = '';
}
$tokens["{{ raw_arguments.{$arg} }}"] = isset($this->view->args[$count]) ? strip_tags(Html::decodeEntities($this->view->args[$count])) : '';
$count++;
}
if ($request = $this->view
->getRequest()) {
$tokens += $this
->getTokenValuesRecursive($request->query
->all());
}
foreach ($this->displayHandler
->getHandlers('field') as $field => $handler) {
$placeholder = $handler
->getFieldTokenPlaceholder();
if (isset($handler->last_render)) {
$tokens[$placeholder] = $handler->last_render;
}
else {
$tokens[$placeholder] = '';
}
if ($field == $this->options['id']) {
break;
}
}
$this->view->style_plugin->render_tokens[$this->view->row_index] = $tokens;
$this->last_tokens = $tokens;
if (!empty($item)) {
$this
->addSelfTokens($tokens, $item);
}
return $tokens;
}
protected function getFieldTokenPlaceholder() {
return '{{ ' . $this->options['id'] . ' }}';
}
protected function getTokenValuesRecursive(array $array, array $parent_keys = array()) {
$tokens = array();
foreach ($array as $param => $val) {
if (is_array($val)) {
$child_parent_keys = $parent_keys;
$child_parent_keys[] = $param;
$child_tokens = $this
->getTokenValuesRecursive($val, $child_parent_keys);
$tokens += $child_tokens;
}
else {
$token_string = !empty($parent_keys) ? implode('.', $parent_keys) . '.' . $param : $param;
$tokens['{{ arguments.' . $token_string . ' }}'] = strip_tags(Html::decodeEntities($val));
}
}
return $tokens;
}
protected function addSelfTokens(&$tokens, $item) {
}
protected function documentSelfTokens(&$tokens) {
}
function theme(ResultRow $values) {
$renderer = $this
->getRenderer();
$build = array(
'#theme' => $this
->themeFunctions(),
'#view' => $this->view,
'#field' => $this,
'#row' => $values,
);
$output = $renderer
->render($build);
$this->view->element = $renderer
->mergeBubbleableMetadata($this->view->element, $build);
return $output;
}
public function themeFunctions() {
$themes = array();
$hook = 'views_view_field';
$display = $this->view->display_handler->display;
if (!empty($display)) {
$themes[] = $hook . '__' . $this->view->storage
->id() . '__' . $display['id'] . '__' . $this->options['id'];
$themes[] = $hook . '__' . $this->view->storage
->id() . '__' . $display['id'];
$themes[] = $hook . '__' . $display['id'] . '__' . $this->options['id'];
$themes[] = $hook . '__' . $display['id'];
if ($display['id'] != $display['display_plugin']) {
$themes[] = $hook . '__' . $this->view->storage
->id() . '__' . $display['display_plugin'] . '__' . $this->options['id'];
$themes[] = $hook . '__' . $this->view->storage
->id() . '__' . $display['display_plugin'];
$themes[] = $hook . '__' . $display['display_plugin'] . '__' . $this->options['id'];
$themes[] = $hook . '__' . $display['display_plugin'];
}
}
$themes[] = $hook . '__' . $this->view->storage
->id() . '__' . $this->options['id'];
$themes[] = $hook . '__' . $this->view->storage
->id();
$themes[] = $hook . '__' . $this->options['id'];
$themes[] = $hook;
return $themes;
}
public function adminLabel($short = FALSE) {
return $this
->getField(parent::adminLabel($short));
}
public static function trimText($alter, $value) {
if (Unicode::strlen($value) > $alter['max_length']) {
$value = Unicode::substr($value, 0, $alter['max_length']);
if (!empty($alter['word_boundary'])) {
$regex = "(.*)\\b.+";
if (function_exists('mb_ereg')) {
mb_regex_encoding('UTF-8');
$found = mb_ereg($regex, $value, $matches);
}
else {
$found = preg_match("/{$regex}/us", $value, $matches);
}
if ($found) {
$value = $matches[1];
}
}
$value = rtrim(preg_replace('/(?:<(?!.+>)|&(?!.+;)).*$/us', '', $value));
if (!empty($alter['ellipsis'])) {
$value .= t('…');
}
}
if (!empty($alter['html'])) {
$value = Html::normalize($value);
}
return $value;
}
protected function linkGenerator() {
if (!isset($this->linkGenerator)) {
$this->linkGenerator = \Drupal::linkGenerator();
}
return $this->linkGenerator;
}
protected function getRenderer() {
if (!isset($this->renderer)) {
$this->renderer = \Drupal::service('renderer');
}
return $this->renderer;
}
}