From d907b8b166e55fc62c2110893f12f65190c6331b Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Tue, 2 Feb 2016 12:08:20 +0000
Subject: [PATCH] Issue #2567339 by Lendude, penyaskito, dawehner: PHP Warning
 when using link field tokens in a view

---
 .../src/Tests/Views/LinkViewsTokensTest.php   | 102 +++++++++
 .../link_test_views/link_test_views.info.yml  |  10 +
 .../views.view.test_link_tokens.yml           | 206 ++++++++++++++++++
 .../views/src/Plugin/views/field/Field.php    |   7 +-
 4 files changed, 323 insertions(+), 2 deletions(-)
 create mode 100644 core/modules/link/src/Tests/Views/LinkViewsTokensTest.php
 create mode 100644 core/modules/link/tests/modules/link_test_views/link_test_views.info.yml
 create mode 100644 core/modules/link/tests/modules/link_test_views/test_views/views.view.test_link_tokens.yml

diff --git a/core/modules/link/src/Tests/Views/LinkViewsTokensTest.php b/core/modules/link/src/Tests/Views/LinkViewsTokensTest.php
new file mode 100644
index 000000000000..558c5a8504cc
--- /dev/null
+++ b/core/modules/link/src/Tests/Views/LinkViewsTokensTest.php
@@ -0,0 +1,102 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\link\Tests\Views\LinkViewsTokensTest.
+ */
+
+namespace Drupal\link\Tests\Views;
+
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\views\Tests\ViewTestBase;
+use Drupal\views\Tests\ViewTestData;
+
+/**
+ * Tests the views integration for link tokens.
+ *
+ * @group link
+ */
+class LinkViewsTokensTest extends ViewTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['link_test_views'];
+
+  /**
+   * Views used by this test.
+   *
+   * @var array
+   */
+  public static $testViews = ['test_link_tokens'];
+
+  /**
+   * The field name used for the link field.
+   *
+   * @var string
+   */
+  protected $fieldName = 'field_link';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    ViewTestData::createTestViews(get_class($this), array('link_test_views'));
+
+    // Create Basic page node type.
+    $this->drupalCreateContentType(array(
+      'type' => 'page',
+      'name' => 'Basic page'
+    ));
+
+    // Create a field.
+    FieldStorageConfig::create(array(
+      'field_name' => $this->fieldName,
+      'type' => 'link',
+      'entity_type' => 'node',
+      'cardinality' => 1,
+    ))->save();
+    FieldConfig::create(array(
+      'field_name' => $this->fieldName,
+      'entity_type' => 'node',
+      'bundle' => 'page',
+      'label' => 'link field',
+    ))->save();
+
+  }
+
+  public function testLinkViewsTokens() {
+    // Array of URI's to test.
+    $uris = [
+      'http://www.drupal.org' => 'Drupal.org',
+    ];
+
+    // Add nodes with the URI's and titles.
+    foreach ($uris as $uri => $title) {
+      $values = array('type' => 'page');
+      $values[$this->fieldName][] = ['uri' => $uri, 'title' => $title, 'options' => ['attributes' => ['class' => 'test-link-class']]];
+      $this->drupalCreateNode($values);
+    }
+
+    $this->drupalGet('test_link_tokens');
+
+    foreach ($uris as $uri => $title) {
+      // Formatted link: {{ field_link }}<br />
+      $this->assertRaw("Formated: <a href=\"$uri\" class=\"test-link-class\">$title</a>");
+
+      // Raw uri: {{ field_link__uri }}<br />
+      $this->assertRaw("Raw uri: $uri");
+
+      // Raw title: {{ field_link__title }}<br />
+      $this->assertRaw("Raw title: $title");
+
+      // Raw options: {{ field_link__options }}<br />
+      // Options is an array and should return empty after token replace.
+      $this->assertRaw("Raw options: .");
+    }
+  }
+}
diff --git a/core/modules/link/tests/modules/link_test_views/link_test_views.info.yml b/core/modules/link/tests/modules/link_test_views/link_test_views.info.yml
new file mode 100644
index 000000000000..235ecb693719
--- /dev/null
+++ b/core/modules/link/tests/modules/link_test_views/link_test_views.info.yml
@@ -0,0 +1,10 @@
+name: 'Link test views'
+type: module
+description: 'Provides default views for views link tests.'
+package: Testing
+version: VERSION
+core: 8.x
+dependencies:
+  - node
+  - views
+  - link
diff --git a/core/modules/link/tests/modules/link_test_views/test_views/views.view.test_link_tokens.yml b/core/modules/link/tests/modules/link_test_views/test_views/views.view.test_link_tokens.yml
new file mode 100644
index 000000000000..2372b1251c64
--- /dev/null
+++ b/core/modules/link/tests/modules/link_test_views/test_views/views.view.test_link_tokens.yml
@@ -0,0 +1,206 @@
+langcode: en
+status: true
+dependencies:
+  config:
+    - field.storage.node.field_link
+  module:
+    - link
+    - node
+    - user
+id: test_link_tokens
+label: link
+module: views
+description: ''
+tag: ''
+base_table: node_field_data
+base_field: nid
+core: 8.x
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: 0
+    display_options:
+      access:
+        type: perm
+        options:
+          perm: 'access content'
+      cache:
+        type: tag
+        options: {  }
+      query:
+        type: views_query
+        options:
+          disable_sql_rewrite: false
+          distinct: false
+          replica: false
+          query_comment: ''
+          query_tags: {  }
+      exposed_form:
+        type: basic
+        options:
+          submit_button: Apply
+          reset_button: false
+          reset_button_label: Reset
+          exposed_sorts_label: 'Sort by'
+          expose_sort_order: true
+          sort_asc_label: Asc
+          sort_desc_label: Desc
+      pager:
+        type: full
+        options:
+          items_per_page: 10
+          offset: 0
+          id: 0
+          total_pages: null
+          expose:
+            items_per_page: false
+            items_per_page_label: 'Items per page'
+            items_per_page_options: '5, 10, 25, 50'
+            items_per_page_options_all: false
+            items_per_page_options_all_label: '- All -'
+            offset: false
+            offset_label: Offset
+          tags:
+            previous: '‹ previous'
+            next: 'next ›'
+            first: '« first'
+            last: 'last »'
+          quantity: 9
+      style:
+        type: default
+      row:
+        type: fields
+        options:
+          default_field_elements: true
+          inline: {  }
+          separator: ''
+          hide_empty: false
+      fields:
+        field_link:
+          id: field_link
+          table: node__field_link
+          field: field_link
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: false
+          alter:
+            alter_text: true
+            text: "Formated: {{ field_link }}<br />\nRaw uri: {{ field_link__uri }}<br />\nRaw title: {{ field_link__title }}<br />\nRaw options: {{ field_link__options }}."
+            make_link: false
+            path: '{{ field_link__uri }}'
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: uri
+          type: link
+          settings:
+            trim_length: 80
+            url_only: false
+            url_plain: false
+            rel: '0'
+            target: '0'
+          group_column: ''
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+          plugin_id: field
+      filters:
+        status:
+          value: true
+          table: node_field_data
+          field: status
+          plugin_id: boolean
+          entity_type: node
+          entity_field: status
+          id: status
+          expose:
+            operator: ''
+          group: 1
+      sorts:
+        created:
+          id: created
+          table: node_field_data
+          field: created
+          order: DESC
+          entity_type: node
+          entity_field: created
+          plugin_id: date
+          relationship: none
+          group_type: group
+          admin_label: ''
+          exposed: false
+          expose:
+            label: ''
+          granularity: second
+      title: link
+      header: {  }
+      footer: {  }
+      empty: {  }
+      relationships: {  }
+      arguments: {  }
+      display_extenders: {  }
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      cacheable: false
+  page_1:
+    display_plugin: page
+    id: page_1
+    display_title: Page
+    position: 1
+    display_options:
+      display_extenders: {  }
+      path: test_link_tokens
+    cache_metadata:
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      cacheable: false
diff --git a/core/modules/views/src/Plugin/views/field/Field.php b/core/modules/views/src/Plugin/views/field/Field.php
index 3da56ab11444..af3dad1269c7 100644
--- a/core/modules/views/src/Plugin/views/field/Field.php
+++ b/core/modules/views/src/Plugin/views/field/Field.php
@@ -22,6 +22,7 @@
 use Drupal\Core\Render\Element;
 use Drupal\Core\Render\RendererInterface;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\views\FieldAPIHandlerTrait;
 use Drupal\views\Entity\Render\EntityFieldRenderer;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -933,8 +934,10 @@ protected function addSelfTokens(&$tokens, $item) {
 
         if (is_object($raw)) {
           $property = $raw->get($id);
-          if (!empty($property)) {
-            $tokens['{{ ' . $this->options['id'] . '__' . $id . ' }}'] = Xss::filterAdmin($property->getValue());
+          // Check if TypedDataInterface is implemented so we know how to render
+          // the item as a string.
+          if (!empty($property) && $property instanceof TypedDataInterface) {
+            $tokens['{{ ' . $this->options['id'] . '__' . $id . ' }}'] = Xss::filterAdmin($property->getString());
           }
           else {
             // Make sure that empty values are replaced as well.
-- 
GitLab