From 1d386c5ddbddc2aa2788c1bb62505b8afdbfb2f9 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Fri, 11 Oct 2019 09:45:04 +0100
Subject: [PATCH] Issue #2894479 by Sam152, alexpott, amateescu, Berdir,
 larowlan: Deprecate the Views relationship from moderated content to the
 "content_moderation_state" entity

---
 .../content_moderation.install                | 35 ++++++++
 .../content_moderation/src/ViewsData.php      |  8 +-
 .../config/install/views.view.latest.yml      | 37 ++++-----
 ...est_content_moderation_base_table_test.yml | 16 ++++
 ...edModerationStateViewsRelationshipTest.php | 80 +++++++++++++++++++
 .../src/Kernel/ViewsDataIntegrationTest.php   |  1 +
 .../relationship/RelationshipPluginBase.php   |  4 +
 7 files changed, 157 insertions(+), 24 deletions(-)
 create mode 100644 core/modules/content_moderation/tests/src/Functional/DeprecatedModerationStateViewsRelationshipTest.php

diff --git a/core/modules/content_moderation/content_moderation.install b/core/modules/content_moderation/content_moderation.install
index 5be700c6de49..455aaa19513b 100644
--- a/core/modules/content_moderation/content_moderation.install
+++ b/core/modules/content_moderation/content_moderation.install
@@ -5,6 +5,41 @@
  * Install, update and uninstall functions for the Content Moderation module.
  */
 
+use Drupal\Component\Render\FormattableMarkup;
+use Drupal\Core\Link;
+
+/**
+ * Implements hook_requirements().
+ */
+function content_moderation_requirements($phase) {
+  $requirements = [];
+
+  if ($phase === 'runtime') {
+    $config = \Drupal::configFactory();
+    $legacy_views = [];
+    foreach ($config->listAll('views.view.') as $view_id) {
+      $view = $config->get($view_id);
+      foreach ($view->get('display') as $display) {
+        if (!empty($display['display_options']['relationships']['moderation_state'])) {
+          $legacy_views[] = Link::createFromRoute($view->get('label'), 'entity.view.edit_form', ['view' => $view->get('id')])->toString();
+        }
+      }
+    }
+    if (!empty($legacy_views)) {
+      $requirements['deprecated_views_relationship'] = [
+        'title' => t('Content Moderation State views relationship'),
+        'description' => t('This installation contains one or more views which is using a relationship to the Content Moderation State entity. This relationship is deprecated and will be removed before 9.0.0. See <a target="_blank" href=":change_record">this change record</a> for information on removing this relationship or alternative solutions. Views that contain this relationship are: @views', [
+          ':change_record' => 'https://www.drupal.org/node/3061099',
+          '@views' => new FormattableMarkup(implode(', ', $legacy_views), []),
+        ]),
+        'severity' => REQUIREMENT_ERROR,
+      ];
+    }
+  }
+
+  return $requirements;
+}
+
 /**
  * Remove the 'content_revision_tracker' table.
  */
diff --git a/core/modules/content_moderation/src/ViewsData.php b/core/modules/content_moderation/src/ViewsData.php
index 305def533616..3649d6ff2f08 100644
--- a/core/modules/content_moderation/src/ViewsData.php
+++ b/core/modules/content_moderation/src/ViewsData.php
@@ -67,7 +67,8 @@ public function getViewsData() {
         'title' => t('Moderation state'),
         'relationship' => [
           'id' => 'standard',
-          'label' => $this->t('@label moderation state', ['@label' => $entity_type->getLabel()]),
+          'title' => $this->t('Deprecated: @label moderation state', ['@label' => $entity_type->getLabel()]),
+          'help' => $this->t('Using a relationship to the Content Moderation State entity type has been deprecated and will be removed before 9.0.0. See <a target="_blank" href=":url">this change record</a> for alternatives.', [':url' => 'https://www.drupal.org/node/3061099']),
           'base' => $content_moderation_state_entity_base_table,
           'base field' => 'content_entity_id',
           'relationship field' => $entity_type->getKey('id'),
@@ -77,6 +78,7 @@ public function getViewsData() {
               'value' => $entity_type_id,
             ],
           ],
+          'deprecated' => 'Moderation state relationships are deprecated in drupal:8.8.0 and is removed in drupal:9.0.0. See https://www.drupal.org/node/3061099',
         ],
         'field' => [
           'id' => 'moderation_state_field',
@@ -92,7 +94,8 @@ public function getViewsData() {
         'title' => t('Moderation state'),
         'relationship' => [
           'id' => 'standard',
-          'label' => $this->t('@label moderation state', ['@label' => $entity_type->getLabel()]),
+          'title' => $this->t('Deprecated: @label moderation state', ['@label' => $entity_type->getLabel()]),
+          'help' => $this->t('Using a relationship to the Content Moderation State entity type has been deprecated and will be removed before 9.0.0. See <a target="_blank" href=":url">this change record</a> for alternatives.', [':url' => 'https://www.drupal.org/node/3061099']),
           'base' => $content_moderation_state_entity_revision_base_table,
           'base field' => 'content_entity_revision_id',
           'relationship field' => $entity_type->getKey('revision'),
@@ -102,6 +105,7 @@ public function getViewsData() {
               'value' => $entity_type_id,
             ],
           ],
+          'deprecated' => 'Moderation state relationships are deprecated in drupal:8.8.0 and is removed in drupal:9.0.0. See https://www.drupal.org/node/3061099',
         ],
         'field' => [
           'id' => 'moderation_state_field',
diff --git a/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.latest.yml b/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.latest.yml
index 62e972e7dd3e..848639d4fc30 100644
--- a/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.latest.yml
+++ b/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.latest.yml
@@ -5,6 +5,7 @@ dependencies:
     - system.menu.main
   module:
     - content_moderation
+    - node
     - user
 id: latest
 label: Latest
@@ -251,11 +252,11 @@ display:
           multi_type: separator
           separator: ', '
           field_api_classes: false
-        moderation_state:
-          id: moderation_state
-          table: content_moderation_state_field_revision
+        moderation_state_1:
+          id: moderation_state_1
+          table: node_field_revision
           field: moderation_state
-          relationship: moderation_state
+          relationship: none
           group_type: group
           admin_label: ''
           label: 'Moderation state'
@@ -299,9 +300,10 @@ display:
           hide_empty: false
           empty_zero: false
           hide_alter_empty: true
-          click_sort_column: target_id
+          click_sort_column: value
           type: content_moderation_state
-          group_column: target_id
+          settings: {  }
+          group_column: value
           group_columns: {  }
           group_rows: true
           delta_limit: 0
@@ -311,9 +313,8 @@ display:
           multi_type: separator
           separator: ', '
           field_api_classes: false
-          entity_type: content_moderation_state
-          entity_field: moderation_state
-          plugin_id: field
+          entity_type: node
+          plugin_id: moderation_state_field
       filters:
         latest_revision:
           id: latest_revision
@@ -338,6 +339,8 @@ display:
             multiple: false
             remember_roles:
               authenticated: authenticated
+            operator_limit_selection: false
+            operator_list: {  }
           is_grouped: false
           group_info:
             label: ''
@@ -357,21 +360,11 @@ display:
       header: {  }
       footer: {  }
       empty: {  }
-      relationships:
-        moderation_state:
-          id: moderation_state
-          table: node_field_revision
-          field: moderation_state
-          relationship: none
-          group_type: group
-          admin_label: 'Content moderation state'
-          required: false
-          entity_type: node
-          plugin_id: standard
+      relationships: {  }
       arguments: {  }
       display_extenders: {  }
     cache_metadata:
-      max-age: 0
+      max-age: -1
       contexts:
         - 'languages:language_content'
         - 'languages:language_interface'
@@ -397,7 +390,7 @@ display:
         context: '0'
         menu_name: main
     cache_metadata:
-      max-age: 0
+      max-age: -1
       contexts:
         - 'languages:language_content'
         - 'languages:language_interface'
diff --git a/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_base_table_test.yml b/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_base_table_test.yml
index 343806f90f5a..9c2f0de36eb3 100644
--- a/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_base_table_test.yml
+++ b/core/modules/content_moderation/tests/modules/content_moderation_test_views/config/install/views.view.test_content_moderation_base_table_test.yml
@@ -399,3 +399,19 @@ display:
         - 'user.node_grants:view'
         - user.permissions
       tags: {  }
+  page_1:
+    display_plugin: page
+    id: page_1
+    display_title: Page
+    position: 1
+    display_options:
+      display_extenders: {  }
+      path: test-content-moderation-base-table-test
+    cache_metadata:
+      max-age: -1
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - 'user.node_grants:view'
+        - user.permissions
+      tags: {  }
diff --git a/core/modules/content_moderation/tests/src/Functional/DeprecatedModerationStateViewsRelationshipTest.php b/core/modules/content_moderation/tests/src/Functional/DeprecatedModerationStateViewsRelationshipTest.php
new file mode 100644
index 000000000000..3bfbd680808d
--- /dev/null
+++ b/core/modules/content_moderation/tests/src/Functional/DeprecatedModerationStateViewsRelationshipTest.php
@@ -0,0 +1,80 @@
+<?php
+
+namespace Drupal\Tests\content_moderation\Functional;
+
+use Drupal\node\Entity\NodeType;
+use Drupal\Tests\BrowserTestBase;
+use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
+
+/**
+ * Test the deprecated views relationships.
+ *
+ * @group content_moderation
+ * @group legacy
+ */
+class DeprecatedModerationStateViewsRelationshipTest extends BrowserTestBase {
+
+  use ContentModerationTestTrait;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = [
+    'node',
+    'content_moderation',
+    'views_ui',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    NodeType::create([
+      'type' => 'moderated',
+    ])->save();
+    $workflow = $this->createEditorialWorkflow();
+    $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'moderated');
+    $workflow->save();
+
+    $this->drupalLogin($this->rootUser);
+  }
+
+  /**
+   * Test how the deprecated relationships appear in the UI.
+   */
+  public function testReportDeprecatedModerationStateRelationships() {
+    // Assert there is a warning in the UI to prevent new users from using the
+    // feature.
+    $this->drupalGet('admin/structure/views/nojs/add-handler/moderated_content/moderated_content/relationship');
+    $this->assertSession()->pageTextContains('Deprecated: Content moderation state');
+    $this->assertSession()->pageTextContains('Using a relationship to the Content Moderation State entity type has been deprecated');
+
+    // Assert by default the deprecation warning does not appear in the status
+    // report.
+    $this->drupalGet('admin/reports/status');
+    $this->assertSession()->pageTextNotContains('Content Moderation State views relationship');
+
+    // Install the views intended for testing the relationship and assert the
+    // warning does appear.
+    $this->container->get('module_installer')->install(['content_moderation_test_views']);
+    $this->drupalGet('admin/reports/status');
+    $this->assertSession()->pageTextContains('Content Moderation State views relationship');
+    $this->assertSession()->linkExists('test_content_moderation_base_table_test');
+    $this->assertSession()->linkByHrefExists('admin/structure/views/view/test_content_moderation_base_table_test');
+  }
+
+  /**
+   * Test the deprecations are triggered when the deprecated code is executed.
+   *
+   * @expectedDeprecation Moderation state relationships are deprecated in drupal:8.8.0 and is removed in drupal:9.0.0. See https://www.drupal.org/node/3061099
+   */
+  public function testCodeDeprecationModerationStateRelationships() {
+    $this->container->get('module_installer')->install(['content_moderation_test_views']);
+    $this->drupalGet('test-content-moderation-base-table-test');
+  }
+
+}
diff --git a/core/modules/content_moderation/tests/src/Kernel/ViewsDataIntegrationTest.php b/core/modules/content_moderation/tests/src/Kernel/ViewsDataIntegrationTest.php
index 7dfb92e4692a..0f6b1be42b92 100644
--- a/core/modules/content_moderation/tests/src/Kernel/ViewsDataIntegrationTest.php
+++ b/core/modules/content_moderation/tests/src/Kernel/ViewsDataIntegrationTest.php
@@ -12,6 +12,7 @@
  * Tests the views integration of content_moderation.
  *
  * @group content_moderation
+ * @group legacy
  */
 class ViewsDataIntegrationTest extends ViewsKernelTestBase {
 
diff --git a/core/modules/views/src/Plugin/views/relationship/RelationshipPluginBase.php b/core/modules/views/src/Plugin/views/relationship/RelationshipPluginBase.php
index 01469727d565..05d675509b23 100644
--- a/core/modules/views/src/Plugin/views/relationship/RelationshipPluginBase.php
+++ b/core/modules/views/src/Plugin/views/relationship/RelationshipPluginBase.php
@@ -125,6 +125,10 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function query() {
+    if (!empty($this->definition['deprecated'])) {
+      @trigger_error($this->definition['deprecated'], E_USER_DEPRECATED);
+    }
+
     // Figure out what base table this relationship brings to the party.
     $table_data = Views::viewsData()->get($this->definition['base']);
     $base_field = empty($this->definition['base field']) ? $table_data['table']['base']['field'] : $this->definition['base field'];
-- 
GitLab