From b523586c88ae750d28cbced7888df01a15e89bcc Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Tue, 21 Jan 2025 18:56:52 +0200
Subject: [PATCH 1/3] Use default:selection handler

---
 private_message.module                        | 46 +++++++++++++
 src/Form/BanUserForm.php                      |  3 +-
 .../NotBlockedUserSelection.php               | 67 -------------------
 .../PrivateMessageThreadMemberWidget.php      |  3 +-
 4 files changed, 50 insertions(+), 69 deletions(-)
 delete mode 100644 src/Plugin/EntityReferenceSelection/NotBlockedUserSelection.php

diff --git a/private_message.module b/private_message.module
index 26f2452c..856a2d6c 100644
--- a/private_message.module
+++ b/private_message.module
@@ -10,12 +10,15 @@ declare(strict_types=1);
 use Drupal\Component\Render\MarkupInterface;
 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\Query\QueryInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Url;
 use Drupal\private_message\Entity\PrivateMessage;
 use Drupal\user\Entity\User;
+use Drupal\user\Plugin\EntityReferenceSelection\UserSelection;
+use Drupal\user\RoleInterface;
 
 /**
  * Implements hook_views_data().
@@ -691,3 +694,46 @@ function private_message_theme_suggestions_private_message_thread_alter(array &$
 function private_message_theme_suggestions_private_message_alter(array &$suggestions, array &$vars): void {
   $suggestions[] = 'private_message__' . $vars['elements']['#view_mode'];
 }
+
+/**
+ * Implements hook_query_TAG_alter().
+ */
+function private_message_query_entity_reference_alter(QueryInterface $query): void {
+  if (!$handler = $query->getMetadata('entity_reference_selection_handler')) {
+    return;
+  }
+  assert($handler instanceof UserSelection);
+
+  $config = $handler->getConfiguration();
+  // Filter out blocked users.
+  if (!empty($config['private_message:not_blocked_user'])) {
+    $use_pm_permission = 'use private messaging system';
+    $roles = array_filter(
+      \Drupal::entityTypeManager()->getStorage('user_role')->loadMultiple(),
+      fn(RoleInterface $role): bool => $role->hasPermission($use_pm_permission),
+    );
+
+    if (!$rids = array_keys($roles)) {
+      // Provide condition which will not return any results.
+      $query->condition('uid');
+      return;
+
+    }
+
+    $current_user_id = \Drupal::currentUser()->id();
+    $subquery = \Drupal::database()->select('private_message_ban', 'pmb')
+      ->fields('pmb', ['target']);
+    $subquery->condition('owner', $current_user_id);
+
+    $query->condition('uid', $subquery, 'NOT IN');
+    if (!in_array('authenticated', $rids)) {
+      $query->condition('roles', $rids, 'IN');
+    }
+
+    $query->condition('uid', $current_user_id, '<>');
+
+    // Cleanup custom configuration.
+    unset($config['private_message:not_blocked_user']);
+    $handler->setConfiguration($config);
+  }
+}
diff --git a/src/Form/BanUserForm.php b/src/Form/BanUserForm.php
index b73c88ce..75462fc5 100644
--- a/src/Form/BanUserForm.php
+++ b/src/Form/BanUserForm.php
@@ -41,9 +41,10 @@ class BanUserForm extends FormBase {
       '#type' => 'entity_autocomplete',
       '#target_type' => 'user',
       '#tags' => FALSE,
-      '#selection_handler' => 'private_message:not_blocked_user',
+      '#selection_handler' => 'default:user',
       '#selection_settings' => [
         'include_anonymous' => FALSE,
+        'private_message:not_blocked_user' => TRUE,
       ],
     ];
 
diff --git a/src/Plugin/EntityReferenceSelection/NotBlockedUserSelection.php b/src/Plugin/EntityReferenceSelection/NotBlockedUserSelection.php
deleted file mode 100644
index 4f240830..00000000
--- a/src/Plugin/EntityReferenceSelection/NotBlockedUserSelection.php
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\private_message\Plugin\EntityReferenceSelection;
-
-use Drupal\Core\Entity\Attribute\EntityReferenceSelection;
-use Drupal\Core\Entity\Query\QueryInterface;
-use Drupal\Core\StringTranslation\TranslatableMarkup;
-use Drupal\user\Plugin\EntityReferenceSelection\UserSelection;
-use Drupal\user\RoleInterface;
-
-/**
- * Provides reference selection for not blocked users.
- */
-#[EntityReferenceSelection(
-  id: "private_message:not_blocked_user",
-  label: new TranslatableMarkup("Not blocked user selection"),
-  group: "private_message",
-  weight: 3,
-  entity_types: ["user"]
-)]
-class NotBlockedUserSelection extends UserSelection {
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS'): QueryInterface {
-    $query = parent::buildEntityQuery($match, $match_operator);
-
-    $rids = $this->getCanUseRids();
-    // Provide condition which will not return any results.
-    if (empty($rids)) {
-      $query->condition('uid');
-      return $query;
-    }
-
-    $subquery = $this->connection->select('private_message_ban', 'pmb')
-      ->fields('pmb', ['target']);
-    $subquery->condition('owner', $this->currentUser->id());
-
-    $query->condition('uid', $subquery, 'NOT IN');
-    if (!in_array('authenticated', $rids)) {
-      $query->condition('roles', $rids, 'IN');
-    }
-
-    $query->condition('uid', $this->currentUser->id(), '<>');
-
-    return $query;
-  }
-
-  /**
-   * Returns role ids with permission to use PM system.
-   *
-   * @return int[]|string[]
-   *   Array of role IDs.
-   */
-  protected function getCanUseRids(): array {
-    $use_pm_permission = 'use private messaging system';
-    $roles = array_filter(
-      $this->entityTypeManager->getStorage('user_role')->loadMultiple(),
-      fn(RoleInterface $role): bool => $role->hasPermission($use_pm_permission),
-    );
-    return array_keys($roles);
-  }
-
-}
diff --git a/src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php b/src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php
index c429729e..a7c188c3 100644
--- a/src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php
+++ b/src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php
@@ -124,9 +124,10 @@ class PrivateMessageThreadMemberWidget extends EntityReferenceAutocompleteWidget
     $element['target_id']['#title'] = $this->t('To');
     $element['target_id']['#required'] = TRUE;
     $element['target_id']['#default_value'] = $items->referencedEntities();
-    $element['target_id']['#selection_handler'] = 'private_message:not_blocked_user';
+    $element['target_id']['#selection_handler'] = 'default:user';
     $element['target_id']['#selection_settings'] = [
       'include_anonymous' => FALSE,
+      'private_message:not_blocked_user' => TRUE,
     ];
     $element['target_id']['#validate_reference'] = TRUE;
 
-- 
GitLab


From 975fd4581438f9cca94c0b4afcebdb6283b5b7a8 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Tue, 21 Jan 2025 20:20:55 +0200
Subject: [PATCH 2/3] Use entity query

---
 private_message.module | 58 ++++++++++++++++++++++--------------------
 1 file changed, 30 insertions(+), 28 deletions(-)

diff --git a/private_message.module b/private_message.module
index 856a2d6c..b030bead 100644
--- a/private_message.module
+++ b/private_message.module
@@ -696,44 +696,46 @@ function private_message_theme_suggestions_private_message_alter(array &$suggest
 }
 
 /**
- * Implements hook_query_TAG_alter().
+ * Implements hook_entity_query_ENTITY_TYPE_alter().
  */
-function private_message_query_entity_reference_alter(QueryInterface $query): void {
+function private_message_entity_query_user_alter(QueryInterface $query): void {
   if (!$handler = $query->getMetadata('entity_reference_selection_handler')) {
     return;
   }
-  assert($handler instanceof UserSelection);
+  if (!$handler instanceof UserSelection) {
+    return;
+  }
 
-  $config = $handler->getConfiguration();
   // Filter out blocked users.
-  if (!empty($config['private_message:not_blocked_user'])) {
-    $use_pm_permission = 'use private messaging system';
-    $roles = array_filter(
-      \Drupal::entityTypeManager()->getStorage('user_role')->loadMultiple(),
-      fn(RoleInterface $role): bool => $role->hasPermission($use_pm_permission),
-    );
-
-    if (!$rids = array_keys($roles)) {
-      // Provide condition which will not return any results.
-      $query->condition('uid');
-      return;
+  $config = $handler->getConfiguration();
+  if (empty($config['private_message:not_blocked_user'])) {
+    return;
+  }
 
-    }
+  // Cleanup custom configuration.
+  unset($config['private_message:not_blocked_user']);
+  $handler->setConfiguration($config);
 
-    $current_user_id = \Drupal::currentUser()->id();
-    $subquery = \Drupal::database()->select('private_message_ban', 'pmb')
-      ->fields('pmb', ['target']);
-    $subquery->condition('owner', $current_user_id);
+  $roles = array_filter(
+    \Drupal::entityTypeManager()->getStorage('user_role')->loadMultiple(),
+    fn(RoleInterface $role): bool => $role->hasPermission('use private messaging system'),
+  );
 
-    $query->condition('uid', $subquery, 'NOT IN');
-    if (!in_array('authenticated', $rids)) {
-      $query->condition('roles', $rids, 'IN');
-    }
+  if (!$rids = array_keys($roles)) {
+    // Provide condition which will not return any results.
+    $query->condition('uid');
+    return;
+  }
 
-    $query->condition('uid', $current_user_id, '<>');
+  $current_user_id = \Drupal::currentUser()->id();
+  $subquery = \Drupal::database()->select('private_message_ban', 'pmb')
+    ->fields('pmb', ['target']);
+  $subquery->condition('owner', $current_user_id);
 
-    // Cleanup custom configuration.
-    unset($config['private_message:not_blocked_user']);
-    $handler->setConfiguration($config);
+  $query->condition('uid', $subquery, 'NOT IN');
+  if (!in_array('authenticated', $rids)) {
+    $query->condition('roles', $rids, 'IN');
   }
+
+  $query->condition('uid', $current_user_id, '<>');
 }
-- 
GitLab


From 52d7bbb057e21fb1d1d5a7f0dd035b99d8c54663 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Thu, 23 Jan 2025 11:51:52 +0200
Subject: [PATCH 3/3] Honour config schema

---
 private_message.module                        | 21 ++++++++++++++-----
 src/Form/BanUserForm.php                      |  5 ++++-
 .../PrivateMessageThreadMemberWidget.php      |  5 ++++-
 3 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/private_message.module b/private_message.module
index b030bead..0ff0ffab 100644
--- a/private_message.module
+++ b/private_message.module
@@ -708,14 +708,10 @@ function private_message_entity_query_user_alter(QueryInterface $query): void {
 
   // Filter out blocked users.
   $config = $handler->getConfiguration();
-  if (empty($config['private_message:not_blocked_user'])) {
+  if (empty($config['private_message']['active_users_selection'])) {
     return;
   }
 
-  // Cleanup custom configuration.
-  unset($config['private_message:not_blocked_user']);
-  $handler->setConfiguration($config);
-
   $roles = array_filter(
     \Drupal::entityTypeManager()->getStorage('user_role')->loadMultiple(),
     fn(RoleInterface $role): bool => $role->hasPermission('use private messaging system'),
@@ -739,3 +735,18 @@ function private_message_entity_query_user_alter(QueryInterface $query): void {
 
   $query->condition('uid', $current_user_id, '<>');
 }
+
+/**
+ * Implements hook_config_schema_info_alter().
+ */
+function private_message_config_schema_info_alter(array &$definitions): void {
+  if (isset($definitions['entity_reference_selection.default:user'])) {
+    // Required to pass config_inspector validation.
+    $definitions['entity_reference_selection.default:user']['mapping']['private_message'] = [
+      'active_users_selection' => [
+        'type' => 'boolean',
+        'label' => 'Whether to filter out blocked user on member selection widget',
+      ],
+    ];
+  }
+}
diff --git a/src/Form/BanUserForm.php b/src/Form/BanUserForm.php
index 75462fc5..a2ba5bda 100644
--- a/src/Form/BanUserForm.php
+++ b/src/Form/BanUserForm.php
@@ -44,7 +44,10 @@ class BanUserForm extends FormBase {
       '#selection_handler' => 'default:user',
       '#selection_settings' => [
         'include_anonymous' => FALSE,
-        'private_message:not_blocked_user' => TRUE,
+        // @see \private_message_entity_query_user_alter()
+        'private_message' => [
+          'active_users_selection' => TRUE,
+        ],
       ],
     ];
 
diff --git a/src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php b/src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php
index a7c188c3..8cfa8272 100644
--- a/src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php
+++ b/src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php
@@ -127,7 +127,10 @@ class PrivateMessageThreadMemberWidget extends EntityReferenceAutocompleteWidget
     $element['target_id']['#selection_handler'] = 'default:user';
     $element['target_id']['#selection_settings'] = [
       'include_anonymous' => FALSE,
-      'private_message:not_blocked_user' => TRUE,
+      // @see \private_message_entity_query_user_alter()
+      'private_message' => [
+        'active_users_selection' => TRUE,
+      ],
     ];
     $element['target_id']['#validate_reference'] = TRUE;
 
-- 
GitLab