From bedbaf7267cd481ab812493a53e7810b45f14403 Mon Sep 17 00:00:00 2001
From: catch <catch@35733.no-reply.drupal.org>
Date: Tue, 3 Sep 2019 17:27:59 +0100
Subject: [PATCH] Issue #3006815 by plach, gmaka, mudassar774, amateescu,
 Lendude: ViewsEntitySchemaSubscriber may fail when a view has a broken
 handler

---
 .../ViewsEntitySchemaSubscriber.php           |  8 ++++----
 .../views_test_config.module                  | 19 +++++++++++++++++++
 ...sEntitySchemaSubscriberIntegrationTest.php | 19 +++++++++++++++++++
 3 files changed, 42 insertions(+), 4 deletions(-)
 create mode 100644 core/modules/views/tests/modules/views_test_config/views_test_config.module

diff --git a/core/modules/views/src/EventSubscriber/ViewsEntitySchemaSubscriber.php b/core/modules/views/src/EventSubscriber/ViewsEntitySchemaSubscriber.php
index 967714449bf9..85503cbcf591 100644
--- a/core/modules/views/src/EventSubscriber/ViewsEntitySchemaSubscriber.php
+++ b/core/modules/views/src/EventSubscriber/ViewsEntitySchemaSubscriber.php
@@ -306,7 +306,7 @@ protected function baseTableRename($all_views, $entity_type_id, $old_base_table,
       }
     }
 
-    $this->processHandlers($all_views, function (array &$handler_config, ViewEntityInterface $view) use ($entity_type_id, $old_base_table, $new_base_table) {
+    $this->processHandlers($all_views, function (&$handler_config, ViewEntityInterface $view) use ($entity_type_id, $old_base_table, $new_base_table) {
       if (isset($handler_config['entity_type']) && $handler_config['entity_type'] == $entity_type_id && $handler_config['table'] == $old_base_table) {
         $handler_config['table'] = $new_base_table;
         $view->set('_updated', TRUE);
@@ -334,7 +334,7 @@ protected function dataTableRename($all_views, $entity_type_id, $old_data_table,
       }
     }
 
-    $this->processHandlers($all_views, function (array &$handler_config, ViewEntityInterface $view) use ($entity_type_id, $old_data_table, $new_data_table) {
+    $this->processHandlers($all_views, function (&$handler_config, ViewEntityInterface $view) use ($entity_type_id, $old_data_table, $new_data_table) {
       if (isset($handler_config['entity_type']) && $handler_config['entity_type'] == $entity_type_id && $handler_config['table'] == $old_data_table) {
         $handler_config['table'] = $new_data_table;
         $view->set('_updated', TRUE);
@@ -365,7 +365,7 @@ protected function dataTableAddition($all_views, EntityTypeInterface $entity_typ
 
     $data_table = $new_data_table;
 
-    $this->processHandlers($all_views, function (array &$handler_config, ViewEntityInterface $view) use ($entity_type_id, $base_table, $data_table, $base_table_fields, $data_table_fields) {
+    $this->processHandlers($all_views, function (&$handler_config, ViewEntityInterface $view) use ($entity_type_id, $base_table, $data_table, $base_table_fields, $data_table_fields) {
       if (isset($handler_config['entity_type']) && isset($handler_config['entity_field']) && $handler_config['entity_type'] == $entity_type_id) {
         // Move all fields which just exists on the data table.
         if ($handler_config['table'] == $base_table && in_array($handler_config['entity_field'], $data_table_fields) && !in_array($handler_config['entity_field'], $base_table_fields)) {
@@ -390,7 +390,7 @@ protected function dataTableAddition($all_views, EntityTypeInterface $entity_typ
    */
   protected function dataTableRemoval($all_views, $entity_type_id, $old_data_table, $base_table) {
     // We move back the data table back to the base table.
-    $this->processHandlers($all_views, function (array &$handler_config, ViewEntityInterface $view) use ($entity_type_id, $old_data_table, $base_table) {
+    $this->processHandlers($all_views, function (&$handler_config, ViewEntityInterface $view) use ($entity_type_id, $old_data_table, $base_table) {
       if (isset($handler_config['entity_type']) && $handler_config['entity_type'] == $entity_type_id) {
         if ($handler_config['table'] == $old_data_table) {
           $handler_config['table'] = $base_table;
diff --git a/core/modules/views/tests/modules/views_test_config/views_test_config.module b/core/modules/views/tests/modules/views_test_config/views_test_config.module
new file mode 100644
index 000000000000..b631c47a9cf1
--- /dev/null
+++ b/core/modules/views/tests/modules/views_test_config/views_test_config.module
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * @file
+ * Contains the "views_test_config" module main functionality.
+ */
+
+/**
+ * Implements hook_ENTITY_TYPE_load().
+ */
+function views_test_config_view_load(array $views) {
+  // Emulate a severely broken view: this kind of view configuration cannot be
+  // saved, it can likely be returned only by a corrupt active configuration.
+  $broken_view_id = \Drupal::state()->get('views_test_config.broken_view');
+  if (isset($views[$broken_view_id])) {
+    $display =& $views[$broken_view_id]->getDisplay('default');
+    $display['display_options']['fields']['id_broken'] = NULL;
+  }
+}
diff --git a/core/modules/views/tests/src/Kernel/EventSubscriber/ViewsEntitySchemaSubscriberIntegrationTest.php b/core/modules/views/tests/src/Kernel/EventSubscriber/ViewsEntitySchemaSubscriberIntegrationTest.php
index 0e85503e05a4..4a27c0fec1a0 100644
--- a/core/modules/views/tests/src/Kernel/EventSubscriber/ViewsEntitySchemaSubscriberIntegrationTest.php
+++ b/core/modules/views/tests/src/Kernel/EventSubscriber/ViewsEntitySchemaSubscriberIntegrationTest.php
@@ -501,6 +501,25 @@ public function testViewSaveException() {
     ]);
   }
 
+  /**
+   * Tests that broken views are handled gracefully.
+   */
+  public function testBrokenView() {
+    $view_id = 'test_view_entity_test';
+    $this->state->set('views_test_config.broken_view', $view_id);
+    $this->updateEntityTypeToTranslatable(TRUE);
+
+    /** @var \Drupal\views\Entity\View $view */
+    $entity_storage = $this->entityTypeManager->getStorage('view');
+    $view = $entity_storage->load($view_id);
+
+    // The broken handler should have been removed.
+    $display = $view->getDisplay('default');
+    $this->assertFalse(isset($display['display_options']['fields']['id_broken']));
+
+    $this->assertUpdatedViews([$view_id]);
+  }
+
   /**
    * Gets a view and its display.
    *
-- 
GitLab