From 5c20be3a7ef29b1c770ef2bd82ba171accfb178a Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Wed, 2 Oct 2019 17:20:48 +0100
Subject: [PATCH] Issue #3082644 by mikelutz, hchonov, tim.plunkett: Properly
 deprecate type => 'hidden' component handling and
 EntityDisplayBase::handleHiddenType

---
 .../Drupal/Core/Entity/EntityDisplayBase.php  |  21 +++-
 .../d7_field_formatter_settings.yml           |   6 +
 .../Kernel/FieldLayoutEntityDisplayTest.php   |  15 +--
 .../Core/Entity/EntityDisplayBaseTest.php     |   8 +-
 .../Entity/LegacyEntityDisplayBaseTest.php    | 103 ++++++++++++++++++
 5 files changed, 135 insertions(+), 18 deletions(-)
 create mode 100644 core/tests/Drupal/KernelTests/Core/Entity/LegacyEntityDisplayBaseTest.php

diff --git a/core/lib/Drupal/Core/Entity/EntityDisplayBase.php b/core/lib/Drupal/Core/Entity/EntityDisplayBase.php
index 4ab69cb98ef2..3df078a06bfa 100644
--- a/core/lib/Drupal/Core/Entity/EntityDisplayBase.php
+++ b/core/lib/Drupal/Core/Entity/EntityDisplayBase.php
@@ -186,7 +186,7 @@ protected function init() {
           // @todo Remove handling of 'type' in https://www.drupal.org/node/2799641.
           if (!isset($options['region']) && !empty($options['type']) && $options['type'] === 'hidden') {
             $options['region'] = 'hidden';
-            @trigger_error("Specifying 'type' => 'hidden' is deprecated, use 'region' => 'hidden' instead.", E_USER_DEPRECATED);
+            @trigger_error("Support for using 'type' => 'hidden' in a component is deprecated in drupal:8.3.0 and is removed from drupal:9.0.0. Use 'region' => 'hidden' instead. See https://www.drupal.org/node/2801513", E_USER_DEPRECATED);
           }
 
           if (!empty($options['region']) && $options['region'] === 'hidden') {
@@ -253,7 +253,13 @@ public function id() {
   public function preSave(EntityStorageInterface $storage) {
     // Ensure that a region is set on each component.
     foreach ($this->getComponents() as $name => $component) {
-      $this->handleHiddenType($name, $component);
+      // @todo Remove this BC layer in Drupal 9.
+      // @see https://www.drupal.org/project/drupal/issues/2799641
+      if (!isset($component['region']) && isset($component['type']) && $component['type'] === 'hidden') {
+        @trigger_error("Support for using 'type' => 'hidden' in a component is deprecated in drupal:8.3.0 and is removed from drupal:9.0.0. Use 'region' => 'hidden' instead. See https://www.drupal.org/node/2801513", E_USER_DEPRECATED);
+        $this->removeComponent($name);
+      }
+
       // Ensure that a region is set.
       if (isset($this->content[$name]) && !isset($component['region'])) {
         // Directly set the component to bypass other changes in setComponent().
@@ -269,16 +275,21 @@ public function preSave(EntityStorageInterface $storage) {
   /**
    * Handles a component type of 'hidden'.
    *
-   * @deprecated This method exists only for backwards compatibility.
-   *
-   * @todo Remove this in https://www.drupal.org/node/2799641.
+   * The logic of this method has been duplicated inline in the preSave()
+   * method so that this method may remain deprecated and trigger an error.
    *
    * @param string $name
    *   The name of the component.
    * @param array $component
    *   The component array.
+   *
+   * @deprecated in drupal:8.3.0 and is removed from drupal:9.0.0. No
+   *   replacement is provided.
+   *
+   * @see https://www.drupal.org/node/2801513
    */
   protected function handleHiddenType($name, array $component) {
+    @trigger_error(__METHOD__ . ' is deprecated in drupal:8.3.0 and is removed from drupal:9.0.0. No replacement is provided. See https://www.drupal.org/node/2801513', E_USER_DEPRECATED);
     if (!isset($component['region']) && isset($component['type']) && $component['type'] === 'hidden') {
       $this->removeComponent($name);
     }
diff --git a/core/modules/field/migrations/d7_field_formatter_settings.yml b/core/modules/field/migrations/d7_field_formatter_settings.yml
index b4580a235603..f41575fdc874 100644
--- a/core/modules/field/migrations/d7_field_formatter_settings.yml
+++ b/core/modules/field/migrations/d7_field_formatter_settings.yml
@@ -80,6 +80,12 @@ process:
     -
       plugin: skip_on_empty
       method: row
+  hidden:
+    plugin: static_map
+    source: "@options/type"
+    map:
+      hidden: true
+    default_value: false
   "options/settings":
     plugin: default_value
     source: 'formatter/settings'
diff --git a/core/modules/field_layout/tests/src/Kernel/FieldLayoutEntityDisplayTest.php b/core/modules/field_layout/tests/src/Kernel/FieldLayoutEntityDisplayTest.php
index e0d450eb4e5d..230493db80b4 100644
--- a/core/modules/field_layout/tests/src/Kernel/FieldLayoutEntityDisplayTest.php
+++ b/core/modules/field_layout/tests/src/Kernel/FieldLayoutEntityDisplayTest.php
@@ -29,9 +29,11 @@ public function testPreSave() {
       'status' => TRUE,
       'content' => [
         'foo' => ['type' => 'visible'],
-        'bar' => ['type' => 'hidden'],
         'name' => ['type' => 'hidden', 'region' => 'content'],
       ],
+      'hidden' => [
+        'bar' => TRUE,
+      ],
     ]);
 
     $expected = [
@@ -54,11 +56,10 @@ public function testPreSave() {
         'foo' => [
           'type' => 'visible',
         ],
-        'bar' => [
-          'type' => 'hidden',
-        ],
       ],
-      'hidden' => [],
+      'hidden' => [
+        'bar' => TRUE,
+      ],
     ];
     $this->assertEntityValues($expected, $entity_display->toArray());
 
@@ -76,10 +77,6 @@ public function testPreSave() {
     $expected['third_party_settings']['entity_test'] = ['foo' => 'bar'];
     // The visible field is assigned the default region.
     $expected['content']['foo']['region'] = 'content';
-    // The hidden field is removed from the list of visible fields, and marked
-    // as hidden.
-    unset($expected['content']['bar']);
-    $expected['hidden'] = ['bar' => TRUE];
 
     $this->assertEntityValues($expected, $entity_display->toArray());
 
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityDisplayBaseTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityDisplayBaseTest.php
index 258301f6fe9d..7237d2413e5a 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/EntityDisplayBaseTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityDisplayBaseTest.php
@@ -41,14 +41,13 @@ public function testPreSave() {
       'status' => TRUE,
       'content' => [
         'foo' => ['type' => 'visible'],
-        'bar' => ['type' => 'hidden'],
+        'bar' => ['region' => 'hidden'],
         'name' => ['type' => 'hidden', 'region' => 'content'],
       ],
     ]);
 
     // Ensure that no region is set on the component.
     $this->assertArrayNotHasKey('region', $entity_display->getComponent('foo'));
-    $this->assertArrayNotHasKey('region', $entity_display->getComponent('bar'));
 
     // Ensure that a region is set on the component after saving.
     $entity_display->save();
@@ -58,8 +57,9 @@ public function testPreSave() {
     $this->assertArrayHasKey('region', $component);
     $this->assertSame('content', $component['region']);
 
-    // The component with a hidden type has been removed.
-    $this->assertNull($entity_display->getComponent('bar'));
+    $component = $entity_display->getComponent('bar');
+    $this->assertArrayHasKey('region', $component);
+    $this->assertSame('hidden', $component['region']);
 
     // The component with a valid region and hidden type is unchanged.
     $component = $entity_display->getComponent('name');
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/LegacyEntityDisplayBaseTest.php b/core/tests/Drupal/KernelTests/Core/Entity/LegacyEntityDisplayBaseTest.php
new file mode 100644
index 000000000000..f7bec4976eb3
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Core/Entity/LegacyEntityDisplayBaseTest.php
@@ -0,0 +1,103 @@
+<?php
+
+namespace Drupal\KernelTests\Core\Entity;
+
+use Drupal\Core\Entity\Entity\EntityViewDisplay;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests Deprecated EntityDisplayBase functionality.
+ *
+ * @group Entity
+ * @group legacy
+ */
+class LegacyEntityDisplayBaseTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'entity_test',
+    'entity_test_third_party',
+    'field',
+    'system',
+    'comment',
+    'user',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->installEntitySchema('comment');
+    $this->installEntitySchema('entity_test');
+    $this->installSchema('user', ['users_data']);
+  }
+
+  /**
+   * Tests legacy handling of 'type' => 'hidden'.
+   *
+   * @group legacy
+   *
+   * @expectedDeprecation Support for using 'type' => 'hidden' in a component is deprecated in drupal:8.3.0 and is removed from drupal:9.0.0. Use 'region' => 'hidden' instead. See https://www.drupal.org/node/2801513
+   */
+  public function testLegacyPreSave() {
+    $entity_display = EntityViewDisplay::create([
+      'targetEntityType' => 'entity_test',
+      'bundle' => 'entity_test',
+      'mode' => 'default',
+      'status' => TRUE,
+      'content' => [
+        'foo' => ['type' => 'visible'],
+        'bar' => ['type' => 'hidden'],
+        'name' => ['type' => 'hidden', 'region' => 'content'],
+      ],
+    ]);
+
+    // Ensure that no region is set on the component.
+    $this->assertArrayNotHasKey('region', $entity_display->getComponent('foo'));
+    $this->assertArrayNotHasKey('region', $entity_display->getComponent('bar'));
+
+    // Ensure that a region is set on the component after saving.
+    $entity_display->save();
+
+    // The component with a visible type has been assigned a region.
+    $component = $entity_display->getComponent('foo');
+    $this->assertArrayHasKey('region', $component);
+    $this->assertSame('content', $component['region']);
+
+    // The component with a hidden type has been removed.
+    $this->assertNull($entity_display->getComponent('bar'));
+
+    // The component with a valid region and hidden type is unchanged.
+    $component = $entity_display->getComponent('name');
+    $this->assertArrayHasKey('region', $component);
+    $this->assertSame('content', $component['region']);
+  }
+
+  /**
+   * Tests the deprecated ::handleHiddenType() method.
+   *
+   * @expectedDeprecation Drupal\Core\Entity\EntityDisplayBase::handleHiddenType is deprecated in drupal:8.3.0 and is removed from drupal:9.0.0. No replacement is provided. See https://www.drupal.org/node/2801513
+   */
+  public function testHandleHiddenType() {
+    $entity_display = EntityViewDisplay::create([
+      'targetEntityType' => 'entity_test',
+      'bundle' => 'entity_test',
+      'mode' => 'default',
+      'status' => TRUE,
+      'content' => [
+        'foo' => ['type' => 'visible'],
+        'bar' => ['type' => 'hidden'],
+        'name' => ['type' => 'hidden', 'region' => 'content'],
+      ],
+    ]);
+    $method = new \ReflectionMethod($entity_display, 'handleHiddenType');
+    $method->setAccessible(TRUE);
+    $this->assertSame(['type' => 'hidden'], $entity_display->getComponent('bar'));
+    $method->invoke($entity_display, 'bar', ['type' => 'hidden']);
+    $this->assertNull($entity_display->getComponent('bar'));
+  }
+
+}
-- 
GitLab