Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / modules / views / src / Entity / View.php
index 298c20b3b505797c7ddbbf512e19c861cb071a64..11a0938449c5b1d871170cb1c5c4d15872a07c03 100644 (file)
@@ -5,8 +5,11 @@ namespace Drupal\views\Entity;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Entity\ContentEntityTypeInterface;
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Language\LanguageInterface;
+use Drupal\views\Plugin\DependentWithRemovalPluginInterface;
 use Drupal\views\Views;
 use Drupal\views\ViewEntityInterface;
 
@@ -16,9 +19,14 @@ use Drupal\views\ViewEntityInterface;
  * @ConfigEntityType(
  *   id = "view",
  *   label = @Translation("View", context = "View entity type"),
- *   handlers = {
- *     "access" = "Drupal\views\ViewAccessControlHandler"
- *   },
+ *   label_collection = @Translation("Views", context = "View entity type"),
+ *   label_singular = @Translation("view", context = "View entity type"),
+ *   label_plural = @Translation("views", context = "View entity type"),
+ *   label_count = @PluralTranslation(
+ *     singular = "@count view",
+ *     plural = "@count views",
+ *     context = "View entity type",
+ *   ),
  *   admin_permission = "administer views",
  *   entity_keys = {
  *     "id" = "id",
@@ -245,6 +253,7 @@ class View extends ConfigEntityBase implements ViewEntityInterface {
     $display_duplicate = $displays[$old_display_id];
     unset($display_duplicate['display_title']);
     unset($display_duplicate['display_plugin']);
+    unset($display_duplicate['new_id']);
 
     $displays[$new_display_id] = NestedArray::mergeDeep($displays[$new_display_id], $display_duplicate);
     $displays[$new_display_id]['id'] = $new_display_id;
@@ -290,10 +299,13 @@ class View extends ConfigEntityBase implements ViewEntityInterface {
   public function preSave(EntityStorageInterface $storage) {
     parent::preSave($storage);
 
+    $displays = $this->get('display');
+
+    $this->fixTableNames($displays);
+
     // Sort the displays.
-    $display = $this->get('display');
-    ksort($display);
-    $this->set('display', ['default' => $display['default']] + $display);
+    ksort($displays);
+    $this->set('display', ['default' => $displays['default']] + $displays);
 
     // @todo Check whether isSyncing is needed.
     if (!$this->isSyncing()) {
@@ -301,6 +313,47 @@ class View extends ConfigEntityBase implements ViewEntityInterface {
     }
   }
 
+  /**
+   * Fixes table names for revision metadata fields of revisionable entities.
+   *
+   * Views for revisionable entity types using revision metadata fields might
+   * be using the wrong table to retrieve the fields after system_update_8300
+   * has moved them correctly to the revision table. This method updates the
+   * views to use the correct tables.
+   *
+   * @param array &$displays
+   *   An array containing display handlers of a view.
+   *
+   * @deprecated in Drupal 8.3.0, will be removed in Drupal 9.0.0.
+   *
+   * @see https://www.drupal.org/node/2831499
+   */
+  private function fixTableNames(array &$displays) {
+    // Fix wrong table names for entity revision metadata fields.
+    foreach ($displays as $display => $display_data) {
+      if (isset($display_data['display_options']['fields'])) {
+        foreach ($display_data['display_options']['fields'] as $property_name => $property_data) {
+          if (isset($property_data['entity_type']) && isset($property_data['field']) && isset($property_data['table'])) {
+            $entity_type = $this->entityTypeManager()->getDefinition($property_data['entity_type']);
+            // We need to update the table name only for revisionable entity
+            // types, otherwise the view is already using the correct table.
+            if (($entity_type instanceof ContentEntityTypeInterface) && is_subclass_of($entity_type->getClass(), FieldableEntityInterface::class) && $entity_type->isRevisionable()) {
+              $revision_metadata_fields = $entity_type->getRevisionMetadataKeys();
+              // @see \Drupal\Core\Entity\Sql\SqlContentEntityStorage::initTableLayout()
+              $revision_table = $entity_type->getRevisionTable() ?: $entity_type->id() . '_revision';
+
+              // Check if this is a revision metadata field and if it uses the
+              // wrong table.
+              if (in_array($property_data['field'], $revision_metadata_fields) && $property_data['table'] != $revision_table) {
+                $displays[$display]['display_options']['fields'][$property_name]['table'] = $revision_table;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
   /**
    * Fills in the cache metadata of this view.
    *
@@ -345,7 +398,7 @@ class View extends ConfigEntityBase implements ViewEntityInterface {
     views_invalidate_cache();
     $this->invalidateCaches();
 
-    // Rebuild the router if this is a new view, or it's status changed.
+    // Rebuild the router if this is a new view, or its status changed.
     if (!isset($this->original) || ($this->status() != $this->original->status())) {
       \Drupal::service('router.builder')->setRebuildNeeded();
     }
@@ -378,7 +431,7 @@ class View extends ConfigEntityBase implements ViewEntityInterface {
           'position' => 0,
           'display_options' => [],
         ],
-      ]
+      ],
     ];
   }
 
@@ -414,7 +467,7 @@ class View extends ConfigEntityBase implements ViewEntityInterface {
   public static function postDelete(EntityStorageInterface $storage, array $entities) {
     parent::postDelete($storage, $entities);
 
-    $tempstore = \Drupal::service('user.shared_tempstore')->get('views');
+    $tempstore = \Drupal::service('tempstore.shared')->get('views');
     foreach ($entities as $entity) {
       $tempstore->delete($entity->id());
     }
@@ -468,4 +521,61 @@ class View extends ConfigEntityBase implements ViewEntityInterface {
     \Drupal::service('cache_tags.invalidator')->invalidateTags($tags);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function onDependencyRemoval(array $dependencies) {
+    $changed = FALSE;
+
+    // Don't intervene if the views module is removed.
+    if (isset($dependencies['module']) && in_array('views', $dependencies['module'])) {
+      return FALSE;
+    }
+
+    // If the base table for the View is provided by a module being removed, we
+    // delete the View because this is not something that can be fixed manually.
+    $views_data = Views::viewsData();
+    $base_table = $this->get('base_table');
+    $base_table_data = $views_data->get($base_table);
+    if (!empty($base_table_data['table']['provider']) && in_array($base_table_data['table']['provider'], $dependencies['module'])) {
+      return FALSE;
+    }
+
+    $current_display = $this->getExecutable()->current_display;
+    $handler_types = Views::getHandlerTypes();
+
+    // Find all the handlers and check whether they want to do something on
+    // dependency removal.
+    foreach ($this->display as $display_id => $display_plugin_base) {
+      $this->getExecutable()->setDisplay($display_id);
+      $display = $this->getExecutable()->getDisplay();
+
+      foreach (array_keys($handler_types) as $handler_type) {
+        $handlers = $display->getHandlers($handler_type);
+        foreach ($handlers as $handler_id => $handler) {
+          if ($handler instanceof DependentWithRemovalPluginInterface) {
+            if ($handler->onDependencyRemoval($dependencies)) {
+              // Remove the handler and indicate we made changes.
+              unset($this->display[$display_id]['display_options'][$handler_types[$handler_type]['plural']][$handler_id]);
+              $changed = TRUE;
+            }
+          }
+        }
+      }
+    }
+
+    // Disable the View if we made changes.
+    // @todo https://www.drupal.org/node/2832558 Give better feedback for
+    // disabled config.
+    if ($changed) {
+      // Force a recalculation of the dependencies if we made changes.
+      $this->getExecutable()->current_display = NULL;
+      $this->calculateDependencies();
+      $this->disable();
+    }
+
+    $this->getExecutable()->setDisplay($current_display);
+    return $changed;
+  }
+
 }