From 502c857b92a46f18dbf8ddfa1e5562fd053092d0 Mon Sep 17 00:00:00 2001
From: catch <catch@35733.no-reply.drupal.org>
Date: Thu, 14 Dec 2023 12:46:28 +0000
Subject: [PATCH] Issue #3408698 by lauriii, alexpott: Provide alter for the
 field type UI definitions

---
 .../Core/Field/FieldTypePluginManager.php     |  9 +++++++++
 .../Field/FieldTypePluginManagerInterface.php | 14 +++++++++++++
 core/modules/comment/comment.module           | 16 ++++-----------
 core/modules/field/field.api.php              | 20 +++++++++++++++++++
 .../modules/field_test/field_test.module      | 10 ++++++++++
 .../src/Kernel/FieldTypePluginManagerTest.php | 12 +++++++++++
 .../field_ui/src/Form/FieldStorageAddForm.php |  2 +-
 .../tests/src/Functional/ManageFieldsTest.php | 11 ++++++++++
 8 files changed, 81 insertions(+), 13 deletions(-)

diff --git a/core/lib/Drupal/Core/Field/FieldTypePluginManager.php b/core/lib/Drupal/Core/Field/FieldTypePluginManager.php
index 66b17b977fcd..f3f6fe0b52c7 100644
--- a/core/lib/Drupal/Core/Field/FieldTypePluginManager.php
+++ b/core/lib/Drupal/Core/Field/FieldTypePluginManager.php
@@ -226,6 +226,15 @@ public function getUiDefinitions() {
     return $definitions;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getEntityTypeUiDefinitions(string $entity_type_id): array {
+    $ui_definitions = $this->getUiDefinitions();
+    $this->moduleHandler->alter('field_info_entity_type_ui_definitions', $ui_definitions, $entity_type_id);
+    return $ui_definitions;
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/lib/Drupal/Core/Field/FieldTypePluginManagerInterface.php b/core/lib/Drupal/Core/Field/FieldTypePluginManagerInterface.php
index 1473fd2b81d9..b40be64ee5a6 100644
--- a/core/lib/Drupal/Core/Field/FieldTypePluginManagerInterface.php
+++ b/core/lib/Drupal/Core/Field/FieldTypePluginManagerInterface.php
@@ -113,6 +113,20 @@ public function getFieldSettingsSummary(FieldDefinitionInterface $field_definiti
    */
   public function getUiDefinitions();
 
+  /**
+   * Get the field type definitions that can be added via UI for an entity type.
+   *
+   * @param string $entity_type_id
+   *   The entity type id.
+   *
+   * @return array
+   *   An array of field type definitions.
+   *
+   * @see \Drupal\Core\Field\FieldTypePluginManagerInterface::getUiDefinitions()
+   * @see hook_field_info_entity_type_ui_definitions_alter()
+   */
+  public function getEntityTypeUiDefinitions(string $entity_type_id): array;
+
   /**
    * Returns preconfigured field options for a field type.
    *
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index a3a80c8b8331..db13e9a67090 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -238,23 +238,15 @@ function comment_form_field_ui_field_storage_add_form_alter(&$form, FormStateInt
   if ($form_state->get('entity_type_id') == 'comment' && $route_match->getParameter('commented_entity_type')) {
     $form['#title'] = \Drupal::service('comment.manager')->getFieldUIPageTitle($route_match->getParameter('commented_entity_type'), $route_match->getParameter('field_name'));
   }
-  if (!_comment_entity_uses_integer_id($form_state->get('entity_type_id'))) {
-    $form['add']['new_storage_type']['#process'][] = 'comment_new_storage_type_process_callback';
-  }
 }
 
 /**
- * Process callback to remove comment type field option.
+ * Implements hook_field_info_entity_type_ui_definitions_alter().
  */
-function comment_new_storage_type_process_callback($element, &$form_state, $form) {
-  foreach ($element as $key => $value) {
-    if (isset($value['radio']['#return_value']) && $value['radio']['#return_value'] === 'comment') {
-      // You cannot use comment fields on entity types with non-integer IDs.
-      unset($element[$key]);
-    }
+function comment_field_info_entity_type_ui_definitions_alter(array &$ui_definitions, string $entity_type_id) {
+  if (!_comment_entity_uses_integer_id($entity_type_id)) {
+    unset($ui_definitions['comment']);
   }
-
-  return $element;
 }
 
 /**
diff --git a/core/modules/field/field.api.php b/core/modules/field/field.api.php
index ed9b86a8afff..ac963a3952c2 100644
--- a/core/modules/field/field.api.php
+++ b/core/modules/field/field.api.php
@@ -57,6 +57,26 @@ function hook_field_info_alter(&$info) {
   }
 }
 
+/**
+ * Alters the UI field definitions.
+ *
+ * This hook can be used for altering field definitions available in the UI
+ * dynamically per entity type. For example, it can be used to hide field types
+ * that are incompatible with an entity type.
+ *
+ * @param array $ui_definitions
+ *   Definition of all field types that can be added via UI.
+ * @param string $entity_type_id
+ *   The entity type id.
+ *
+ * @see \Drupal\Core\Field\FieldTypePluginManagerInterface::getEntityTypeUiDefinitions
+ */
+function hook_field_info_entity_type_ui_definitions_alter(array &$ui_definitions, string $entity_type_id) {
+  if ($entity_type_id === 'node') {
+    unset($ui_definitions['field_type_not_compatible_with_node']);
+  }
+}
+
 /**
  * Perform alterations on preconfigured field options.
  *
diff --git a/core/modules/field/tests/modules/field_test/field_test.module b/core/modules/field/tests/modules/field_test/field_test.module
index 91ca8c0f9080..f6b2dbf81448 100644
--- a/core/modules/field/tests/modules/field_test/field_test.module
+++ b/core/modules/field/tests/modules/field_test/field_test.module
@@ -15,6 +15,7 @@
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\field\FieldStorageConfigInterface;
 
 require_once __DIR__ . '/field_test.entity.inc';
@@ -215,3 +216,12 @@ function field_test_field_ui_preconfigured_options_alter(array &$options, $field
     ];
   }
 }
+
+/**
+ * Implements hook_field_info_entity_type_ui_definitions_alter().
+ */
+function field_test_field_info_entity_type_ui_definitions_alter(array &$ui_definitions, string $entity_type_id) {
+  if ($entity_type_id === 'node') {
+    $ui_definitions['boolean']['label'] = new TranslatableMarkup('Boolean (overridden by alter)');
+  }
+}
diff --git a/core/modules/field/tests/src/Kernel/FieldTypePluginManagerTest.php b/core/modules/field/tests/src/Kernel/FieldTypePluginManagerTest.php
index 73b769836b28..83aae5e2b4ce 100644
--- a/core/modules/field/tests/src/Kernel/FieldTypePluginManagerTest.php
+++ b/core/modules/field/tests/src/Kernel/FieldTypePluginManagerTest.php
@@ -110,6 +110,18 @@ public function testMainProperty() {
     }
   }
 
+  /**
+   * Tests UI definitions per entity type.
+   */
+  public function testUiDefinitionsPerEntityType() {
+    /** @var \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager */
+    $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
+    $definitions = $field_type_manager->getEntityTypeUiDefinitions('node');
+    $this->assertEquals('Boolean (overridden by alter)', (string) $definitions['boolean']['label']);
+    $definitions = $field_type_manager->getEntityTypeUiDefinitions('entity_test');
+    $this->assertEquals('Boolean', (string) $definitions['boolean']['label']);
+  }
+
   /**
    * Enable all core modules.
    */
diff --git a/core/modules/field_ui/src/Form/FieldStorageAddForm.php b/core/modules/field_ui/src/Form/FieldStorageAddForm.php
index 8c9893184086..6d5ff8bc3145 100644
--- a/core/modules/field_ui/src/Form/FieldStorageAddForm.php
+++ b/core/modules/field_ui/src/Form/FieldStorageAddForm.php
@@ -150,7 +150,7 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t
     ];
 
     $field_type_options = $unique_definitions = [];
-    $grouped_definitions = $this->fieldTypePluginManager->getGroupedDefinitions($this->fieldTypePluginManager->getUiDefinitions(), 'label', 'id');
+    $grouped_definitions = $this->fieldTypePluginManager->getGroupedDefinitions($this->fieldTypePluginManager->getEntityTypeUiDefinitions($this->entityTypeId), 'label', 'id');
     $category_definitions = $this->fieldTypeCategoryManager->getDefinitions();
     // Invoke a hook to get category properties.
     foreach ($grouped_definitions as $category => $field_types) {
diff --git a/core/modules/field_ui/tests/src/Functional/ManageFieldsTest.php b/core/modules/field_ui/tests/src/Functional/ManageFieldsTest.php
index aa4448868050..8bd98ebe26f9 100644
--- a/core/modules/field_ui/tests/src/Functional/ManageFieldsTest.php
+++ b/core/modules/field_ui/tests/src/Functional/ManageFieldsTest.php
@@ -345,4 +345,15 @@ public function testFieldTypeCardinalityAlter() {
     $this->assertSession()->elementTextContains('css', '#edit-field-storage', 'Greetings from Drupal\field_test\Plugin\Field\FieldType\TestItem::storageSettingsForm');
   }
 
+  /**
+   * Tests hook_field_info_entity_type_ui_definitions_alter().
+   */
+  public function testFieldUiDefinitionsAlter() {
+    $user = $this->drupalCreateUser(['administer node fields']);
+    $node_type = $this->drupalCreateContentType();
+    $this->drupalLogin($user);
+    $this->drupalGet('/admin/structure/types/manage/' . $node_type->id() . '/fields/add-field');
+    $this->assertSession()->pageTextContains('Boolean (overridden by alter)');
+  }
+
 }
-- 
GitLab