From 5ba2a02bcf49b50e3717e1489f2c1b32914fe9c2 Mon Sep 17 00:00:00 2001
From: Carsten Logemann <C_Logemann.dev@nodegard.com>
Date: Fri, 14 Feb 2025 15:25:22 +0100
Subject: [PATCH] Issue #3506678 by c-logemann: Remove Entity Reference UUID
 dependency

---
 composer.json                                 |  3 -
 grant.info.yml                                |  1 -
 grant.install                                 | 47 +++++++++
 grant.views.inc                               | 40 +++++++-
 modules/grant_base/grant_base.info.yml        |  2 +-
 src/Entity/Grant.php                          | 14 +--
 .../views/relationship/GrantStandardUuid.php  | 97 +++++++++++++++++++
 7 files changed, 190 insertions(+), 14 deletions(-)
 create mode 100644 grant.install
 create mode 100644 src/Plugin/views/relationship/GrantStandardUuid.php

diff --git a/composer.json b/composer.json
index 69f6d01..424456f 100644
--- a/composer.json
+++ b/composer.json
@@ -15,8 +15,5 @@
     "support": {
         "issues": "https://www.drupal.org/project/issues/grant",
         "source": "http://cgit.drupalcode.org/grant"
-    },
-    "require": {
-        "drupal/entity_reference_uuid": "^2.0"
     }
 }
diff --git a/grant.info.yml b/grant.info.yml
index 2ffb0aa..4fc1704 100644
--- a/grant.info.yml
+++ b/grant.info.yml
@@ -4,4 +4,3 @@ description: Grant allows role assignments to entities based on mail addresses.
 core_version_requirement: ^10.4 || ^11.1
 dependencies:
   - grant:grant_base
-  - entity_reference_uuid:entity_reference_uuid
diff --git a/grant.install b/grant.install
new file mode 100644
index 0000000..d5e6302
--- /dev/null
+++ b/grant.install
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the Grant module.
+ */
+
+use Drupal\Core\Field\BaseFieldDefinition;
+
+/**
+ * Implements hook_update_N().
+ */
+function grant_update_10001() {
+  $database = \Drupal::database();
+  $transaction = $database->startTransaction();
+  $definition_manager = \Drupal::entityDefinitionUpdateManager();
+
+  // Store the existing values.
+  $values = $database->select('grant')->fields('grant', ['uuid', 'user', 'assignee'])->execute()->fetchAll();
+
+  // Clear out the values.
+  $database->update('grant')->fields(['user' => NULL, 'assignee' => NULL])->execute();
+
+  // Uninstall the fields.
+  $field_storage_definition = $definition_manager->getFieldStorageDefinition('user', 'grant');
+  $definition_manager->uninstallFieldStorageDefinition($field_storage_definition);
+  $field_storage_definition = $definition_manager->getFieldStorageDefinition('assignee', 'grant');
+  $definition_manager->uninstallFieldStorageDefinition($field_storage_definition);
+
+  // Create new field definitions.
+  $new_user_field = BaseFieldDefinition::create('string')->setLabel(t('User'))->setSetting('max_length', 128);
+  $new_assignee_field = BaseFieldDefinition::create('string')->setLabel(t('Assignee'))->setSetting('max_length', 128);
+
+  // Install the new definitions.
+  $definition_manager->installFieldStorageDefinition('user', 'grant', 'grant', $new_user_field);
+  $definition_manager->installFieldStorageDefinition('assignee', 'grant', 'grant', $new_assignee_field);
+
+  // Restore the values.
+  foreach ($values as $value) {
+    $database->update('grant')->fields(['user' => $value->user, 'assignee' => $value->assignee])
+      ->condition('uuid', $value->uuid)->execute();
+  }
+
+  // Commit transaction.
+  unset($transaction);
+  return t('All grants updated.');
+}
diff --git a/grant.views.inc b/grant.views.inc
index 9571025..de1c1c3 100644
--- a/grant.views.inc
+++ b/grant.views.inc
@@ -1,7 +1,5 @@
 <?php
 
-declare(strict_types=1);
-
 /**
  * @file
  * Views hooks for the Grant module.
@@ -23,4 +21,42 @@ function grant_views_data_alter(array &$data) {
     'id' => 'grant_role_label',
   ];
 
+  $args = [
+    '@label' => 'account',
+    '@field_name' => 'grant user field',
+  ];
+  $data['grant']['user']['relationship'] = [
+    'title' => t('@label referenced from @field_name', $args),
+    'label' => t('@field_name: @label', $args),
+    'group' => 'grant',
+    'help' => t('Appears in each grant'),
+    // @see \Drupal\views\Plugin\views\relationship\Standard
+    'id' => 'grant_standard_uuid',
+    'base' => 'users_field_data',
+    'entity base table' => 'users',
+    'entity uuid field' => 'uuid',
+    'entity type' => 'user',
+    'base field' => 'uid',
+    'relationship field' => 'user',
+  ];
+
+  $args = [
+    '@label' => 'account',
+    '@field_name' => 'grant assignee field',
+  ];
+  $data['grant']['assignee']['relationship'] = [
+    'title' => t('@label referenced from @field_name', $args),
+    'label' => t('@field_name: @label', $args),
+    'group' => 'grant',
+    'help' => t('Appears in each grant'),
+    // @see \Drupal\views\Plugin\views\relationship\Standard
+    'id' => 'grant_standard_uuid',
+    'base' => 'users_field_data',
+    'entity base table' => 'users',
+    'entity uuid field' => 'uuid',
+    'entity type' => 'user',
+    'base field' => 'uid',
+    'relationship field' => 'assignee',
+  ];
+
 }
diff --git a/modules/grant_base/grant_base.info.yml b/modules/grant_base/grant_base.info.yml
index a666454..900f68b 100644
--- a/modules/grant_base/grant_base.info.yml
+++ b/modules/grant_base/grant_base.info.yml
@@ -1,4 +1,4 @@
 name: Grant base
 type: module
 description: 'Grant basic functionality can be used without role assignments.'
-core_version_requirement: ^9 || ^10
+core_version_requirement: ^10 || ^11
diff --git a/src/Entity/Grant.php b/src/Entity/Grant.php
index f278272..089c5b3 100644
--- a/src/Entity/Grant.php
+++ b/src/Entity/Grant.php
@@ -110,23 +110,23 @@ class Grant extends ContentEntityBase implements GrantInterface {
       ->setLabel(t('Changed'))
       ->setDescription(t('The time that the grant was last edited.'));
 
-    $fields['user'] = BaseFieldDefinition::create('entity_reference_uuid')
+    $fields['user'] = BaseFieldDefinition::create('string')
       ->setLabel(t('Grant user'))
-      ->setSetting('target_type', 'user')
+      ->setSetting('max_length', 128)
       ->setDisplayConfigurable('form', TRUE)
       ->setDisplayOptions('form', [
-        'type' => 'entity_reference_autocomplete',
+        'type' => 'string_textfield',
         'weight' => 0,
       ])
       ->setDisplayConfigurable('view', TRUE);
 
-    $fields['assignee'] = BaseFieldDefinition::create('entity_reference_uuid')
+    $fields['assignee'] = BaseFieldDefinition::create('string')
       ->setLabel(t('Assignee'))
-      ->setSetting('target_type', 'user')
+      ->setSetting('max_length', 128)
       ->setDisplayConfigurable('form', TRUE)
       ->setDisplayOptions('form', [
-        'type' => 'entity_reference_autocomplete',
-        'weight' => 0,
+        'type' => 'string_textfield',
+        'weight' => 1,
       ])
       ->setDisplayConfigurable('view', TRUE);
 
diff --git a/src/Plugin/views/relationship/GrantStandardUuid.php b/src/Plugin/views/relationship/GrantStandardUuid.php
new file mode 100644
index 0000000..bc080cf
--- /dev/null
+++ b/src/Plugin/views/relationship/GrantStandardUuid.php
@@ -0,0 +1,97 @@
+<?php
+
+namespace Drupal\grant\Plugin\views\relationship;
+
+use Drupal\views\Plugin\views\relationship\Standard;
+use Drupal\views\Views;
+
+/**
+ * Implementation of a relationship plugin for UUID.
+ *
+ * @ingroup views_relationship_handlers
+ *
+ * @ViewsRelationship("grant_standard_uuid")
+ */
+class GrantStandardUuid extends Standard {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+
+    // 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'];
+
+    // Unset provider to avoid duplicates.
+    unset($table_data['table']['provider']);
+
+    $this->ensureMyTable();
+
+    $def = $this->definition;
+
+    // The 'entity base table' is e.g. {node}.
+    $def['table'] = $this->definition['entity base table'];
+    // The 'entity uuid field' is e.g. {node}.uuid.
+    $def['field'] = $this->definition['entity uuid field'];
+    // This is the entity_reference_uuid field table like {node__field_foo}.
+    $def['left_table'] = $this->table;
+    // This is the 'relationship field' like field_foo_target_uuid.
+    $def['left_field'] = $this->realField;
+    if (!empty($this->options['required'])) {
+      $def['type'] = 'INNER';
+    }
+    if (!empty($def['join_id'])) {
+      $id = $def['join_id'];
+    }
+    else {
+      $id = 'standard';
+    }
+    if (!empty($this->definition['extra'])) {
+      $def['extra'] = $this->definition['extra'];
+    }
+    // Join first from e.g. {node__field_foo}.field_foo_target_uuid to
+    // {node}.uuid.
+    $l_join = Views::pluginManager('join')->createInstance($id, $def);
+
+    // Use a short alias for this:
+    $first_alias = $this->definition['entity base table'] . '_' . $this->table . '_' . $this->realField;
+    // And now add our table, using the new relationship if one was used.
+    $alias = $this->query->addTable($this->definition['entity base table'], $this->relationship, $l_join, $first_alias);
+
+    // If there is no data table, the next join is not needed.
+    if ($this->definition['base'] !== $this->definition['entity base table']) {
+      $def = $this->definition;
+      // The data table e.g. {node_field_data}.
+      $def['table'] = $this->definition['base'];
+      // The entity ID field e.g. {node_field_data}.nid.
+      $def['field'] = $base_field;
+      // The alias from the first join to the entity base table e.g. {node}.
+      $def['left_table'] = $alias;
+      // We again use the base field to connect the base and data tables.
+      $def['left_field'] = $base_field;
+      $def['adjusted'] = TRUE;
+      if (!empty($this->options['required'])) {
+        $def['type'] = 'INNER';
+      }
+      // Join next from e.g. {node}.nid to {node_field_data}.nid. This is needed
+      // since uuid is not in the data table.
+      $join = Views::pluginManager('join')->createInstance($id, $def);
+
+      // Use a short alias for this:
+      $alias = $def['table'] . '_' . $this->table . '_' . $this->realField;
+    }
+    else {
+      $join = $l_join;
+    }
+
+    $this->alias = $this->query->addRelationship($alias, $join, $this->definition['base'], $this->relationship);
+
+    // Add access tags if the base table provide it.
+    if (empty($this->query->options['disable_sql_rewrite']) && isset($table_data['table']['base']['access query tag'])) {
+      $access_tag = $table_data['table']['base']['access query tag'];
+      $this->query->addTag($access_tag);
+    }
+  }
+
+}
-- 
GitLab