From 36e6975efc54efe1682b9d20284e4cb925c5de3f Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Tue, 26 Nov 2024 23:00:56 +0200
Subject: [PATCH 01/30] Fix constraints

---
 modules/private_message_notify/private_message_notify.info.yml  | 2 +-
 .../private_message_notify_test.info.yml                        | 2 +-
 private_message.info.yml                                        | 2 +-
 .../modules/private_message_test/private_message_test.info.yml  | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/modules/private_message_notify/private_message_notify.info.yml b/modules/private_message_notify/private_message_notify.info.yml
index 4d664be4..95b84113 100644
--- a/modules/private_message_notify/private_message_notify.info.yml
+++ b/modules/private_message_notify/private_message_notify.info.yml
@@ -2,7 +2,7 @@ name: Private Message Notify
 type: module
 description: Implements new message notifications.
 package: Private Message
-core_version_requirement: ^9.3 || ^10 || ^11
+core_version_requirement: ^10.3 || ^11
 dependencies:
   - message_notify:message_notify
   - private_message:private_message
diff --git a/modules/private_message_notify/tests/modules/private_message_notify_test/private_message_notify_test.info.yml b/modules/private_message_notify/tests/modules/private_message_notify_test/private_message_notify_test.info.yml
index 1189ffd6..88d983ca 100644
--- a/modules/private_message_notify/tests/modules/private_message_notify_test/private_message_notify_test.info.yml
+++ b/modules/private_message_notify/tests/modules/private_message_notify_test/private_message_notify_test.info.yml
@@ -1,6 +1,6 @@
 type: module
 name: Private Message Notify Test
 package: Testing
-core_version_requirement: ^9.3 || ^10 || ^11
+core_version_requirement: ^10.3 || ^11
 dependencies:
   - private_message:private_message_notify
diff --git a/private_message.info.yml b/private_message.info.yml
index c0428b7f..bda6a905 100644
--- a/private_message.info.yml
+++ b/private_message.info.yml
@@ -1,6 +1,6 @@
 name: Private Message
 description: A private message system for users to send messages to each other
-core_version_requirement: ^10 || ^11
+core_version_requirement: ^10.3 || ^11
 type: module
 package: Private Message
 
diff --git a/tests/modules/private_message_test/private_message_test.info.yml b/tests/modules/private_message_test/private_message_test.info.yml
index 6c0acfad..aea113ee 100644
--- a/tests/modules/private_message_test/private_message_test.info.yml
+++ b/tests/modules/private_message_test/private_message_test.info.yml
@@ -1,6 +1,6 @@
 type: module
 name: Private Message Test
 package: Testing
-core_version_requirement: ^9.3 || ^10 || ^11
+core_version_requirement: ^10.3 || ^11
 dependencies:
   - private_message:private_message
-- 
GitLab


From 00f7877ef9b802fb21206dcc8f2fa1dedefc7290 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Tue, 26 Nov 2024 23:17:12 +0200
Subject: [PATCH 02/30] Autowire where possible

---
 .../private_message_notify.services.yml       |  14 +-
 .../src/Service/PrivateMessageNotifier.php    | 120 +++---------
 private_message.install                       |   4 +-
 private_message.services.yml                  |  31 ++--
 .../PrivateMessageThreadCacheContext.php      |  29 +--
 src/Controller/AjaxController.php             | 105 ++---------
 src/Controller/PrivateMessageController.php   | 109 ++---------
 src/Drush/Commands/PrivateMessageCommands.php |  12 +-
 src/Form/BanUserForm.php                      |  73 +-------
 src/Form/ConfigForm.php                       |  53 +++---
 src/Form/ConfirmBanUserForm.php               |  61 +-----
 src/Form/ConfirmUnbanUserForm.php             |  58 +-----
 src/Form/PrivateMessageForm.php               | 173 +++---------------
 src/Mapper/PrivateMessageMapper.php           |  30 +--
 src/Model/BlockType.php                       |  28 +++
 .../PrivateMessageConfigFormManager.php       |  19 +-
 src/Service/PrivateMessageBanManager.php      |  55 +-----
 src/Service/PrivateMessageService.php         |  91 +--------
 src/Service/PrivateMessageThreadManager.php   |  29 +--
 src/Traits/PrivateMessageSettingsTrait.php    |  33 ++++
 20 files changed, 236 insertions(+), 891 deletions(-)
 create mode 100644 src/Model/BlockType.php
 create mode 100644 src/Traits/PrivateMessageSettingsTrait.php

diff --git a/modules/private_message_notify/private_message_notify.services.yml b/modules/private_message_notify/private_message_notify.services.yml
index 1af995bd..45c72776 100644
--- a/modules/private_message_notify/private_message_notify.services.yml
+++ b/modules/private_message_notify/private_message_notify.services.yml
@@ -1,12 +1,8 @@
 services:
+
+  _defaults:
+    autoconfigure: true
+    autowire: true
+
   private_message_notify.notifier:
     class: Drupal\private_message_notify\Service\PrivateMessageNotifier
-    arguments:
-      - '@private_message.service'
-      - '@current_user'
-      - '@user.data'
-      - '@config.factory'
-      - '@entity_type.manager'
-      - '@message_notify.sender'
-      - '@module_handler'
-      - '@logger.factory'
diff --git a/modules/private_message_notify/src/Service/PrivateMessageNotifier.php b/modules/private_message_notify/src/Service/PrivateMessageNotifier.php
index 18d7f735..3983a394 100644
--- a/modules/private_message_notify/src/Service/PrivateMessageNotifier.php
+++ b/modules/private_message_notify/src/Service/PrivateMessageNotifier.php
@@ -12,108 +12,28 @@ use Drupal\message_notify\MessageNotifier;
 use Drupal\private_message\Entity\PrivateMessageInterface;
 use Drupal\private_message\Entity\PrivateMessageThreadInterface;
 use Drupal\private_message\Service\PrivateMessageServiceInterface;
+use Drupal\private_message\Traits\PrivateMessageSettingsTrait;
 use Drupal\user\UserDataInterface;
+use Symfony\Component\DependencyInjection\Attribute\Autowire;
 
 /**
  * A service class for sending notifications of private messages.
  */
 class PrivateMessageNotifier implements PrivateMessageNotifierInterface {
 
-  /**
-   * The private message service.
-   *
-   * @var \Drupal\private_message\Service\PrivateMessageServiceInterface
-   */
-  protected $privateMessageService;
-
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected $currentUser;
-
-  /**
-   * The user data service.
-   *
-   * @var \Drupal\user\UserDataInterface
-   */
-  protected $userData;
-
-  /**
-   * The configuration factory service.
-   *
-   * @var \Drupal\Core\Config\ImmutableConfig
-   */
-  protected $config;
-
-  /**
-   * The entity type manager.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected $entityTypeManager;
-
-  /**
-   * The message notification service.
-   *
-   * @var \Drupal\message_notify\MessageNotifier
-   */
-  protected $messageNotifier;
-
-  /**
-   * The module handler.
-   *
-   * @var \Drupal\Core\Extension\ModuleHandlerInterface
-   */
-  protected $moduleHandler;
+  use PrivateMessageSettingsTrait;
 
-  /**
-   * The logger service for private message notifications.
-   *
-   * @var \Drupal\Core\Logger\LoggerChannelInterface
-   */
-  protected $logger;
-
-  /**
-   * Constructs a new PrivateMessageNotifier object.
-   *
-   * @param \Drupal\private_message\Service\PrivateMessageServiceInterface $privateMessageService
-   *   The private message service.
-   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
-   *   The current user.
-   * @param \Drupal\user\UserDataInterface $userData
-   *   The user data service.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
-   *   The configuration factory service.
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
-   *   The entity type manager service.
-   * @param \Drupal\message_notify\MessageNotifier $messageNotifier
-   *   The message notification service.
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler
-   *   The module handler service.
-   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerFactory
-   *   The logger channel factory.
-   */
   public function __construct(
-    PrivateMessageServiceInterface $privateMessageService,
-    AccountProxyInterface $currentUser,
-    UserDataInterface $userData,
-    ConfigFactoryInterface $configFactory,
-    EntityTypeManagerInterface $entityTypeManager,
-    MessageNotifier $messageNotifier,
-    ModuleHandlerInterface $moduleHandler,
-    LoggerChannelFactoryInterface $loggerFactory,
-  ) {
-    $this->privateMessageService = $privateMessageService;
-    $this->currentUser = $currentUser;
-    $this->userData = $userData;
-    $this->config = $configFactory->get('private_message.settings');
-    $this->entityTypeManager = $entityTypeManager;
-    $this->messageNotifier = $messageNotifier;
-    $this->moduleHandler = $moduleHandler;
-    $this->logger = $loggerFactory->get('private_message_notify');
-  }
+    protected readonly PrivateMessageServiceInterface $privateMessageService,
+    protected readonly AccountProxyInterface $currentUser,
+    protected readonly UserDataInterface $userData,
+    protected readonly ConfigFactoryInterface $configFactory,
+    protected readonly EntityTypeManagerInterface $entityTypeManager,
+    #[Autowire(service: 'message_notify.sender')]
+    protected readonly MessageNotifier $messageNotifier,
+    protected readonly ModuleHandlerInterface $moduleHandler,
+    protected readonly LoggerChannelFactoryInterface $loggerFactory,
+  ) {}
 
   /**
    * {@inheritdoc}
@@ -131,7 +51,10 @@ class PrivateMessageNotifier implements PrivateMessageNotifierInterface {
       $email = $member->getEmail();
       if (empty($email)) {
         // Log a warning if the email is missing, then skip this member.
-        $this->logger->warning('Notification not sent to user ID @uid due to missing email.', ['@uid' => $member->id()]);
+        $this->loggerFactory->get('private_message_notify')
+          ->warning('Notification not sent to user ID @uid due to missing email.', [
+            '@uid' => $member->id(),
+          ]);
         continue;
       }
 
@@ -174,12 +97,11 @@ class PrivateMessageNotifier implements PrivateMessageNotifierInterface {
    *   A boolean indicating whether or not the message should be sent.
    */
   private function shouldSend(AccountInterface $recipient, PrivateMessageInterface $message, PrivateMessageThreadInterface $thread) {
-
     // Don't notify the user by default.
     $notify = FALSE;
 
     // Check if notifications have been enabled.
-    if ($this->config->get('enable_notifications')) {
+    if ($this->getSettings()->get('enable_notifications')) {
 
       // Eligibility to receive notifications will be checked.
       $eligible_to_receive = FALSE;
@@ -192,7 +114,7 @@ class PrivateMessageNotifier implements PrivateMessageNotifierInterface {
       }
       // Check if the user has not made any selection, and the system default is
       // to send:
-      elseif (is_null($user_default) && $this->config->get('notify_by_default')) {
+      elseif (is_null($user_default) && $this->getSettings()->get('notify_by_default')) {
         $eligible_to_receive = TRUE;
       }
 
@@ -207,7 +129,7 @@ class PrivateMessageNotifier implements PrivateMessageNotifierInterface {
         // Check if the user has not yet set a value.
         if (is_null($notify_when_using)) {
           // The user has not yet set a value, so use the system default.
-          $notify_when_using = $this->config->get('notify_when_using');
+          $notify_when_using = $this->getSettings()->get('notify_when_using');
         }
 
         // Get the number of seconds a user has set in their profile, after
@@ -216,7 +138,7 @@ class PrivateMessageNotifier implements PrivateMessageNotifierInterface {
         // Check if the user has not yet set a value.
         if (is_null($away_time)) {
           // The user has not yet set a value, so use the system default.
-          $away_time = $this->config->get('number_of_seconds_considered_away');
+          $away_time = $this->getSettings()->get('number_of_seconds_considered_away');
         }
 
         // Check if users should always be notified.
diff --git a/private_message.install b/private_message.install
index 6b3379dc..cb05f80e 100644
--- a/private_message.install
+++ b/private_message.install
@@ -7,7 +7,7 @@
 
 use Drupal\Core\Database\IntegrityConstraintViolationException;
 use Drupal\Core\Field\BaseFieldDefinition;
-use Drupal\private_message\Form\ConfigForm as Config;
+use Drupal\private_message\Model\BlockType;
 
 /**
  * Implements hook_install().
@@ -394,7 +394,7 @@ function private_message_update_8011() {
  */
 function private_message_update_8012() {
   \Drupal::configFactory()->getEditable('private_message.settings')
-    ->set('ban_mode', Config::PASSIVE)
+    ->set('ban_mode', BlockType::Passive->value)
     ->set('ban_message', 'User is unable to receive your message')
     ->set('ban_label', 'Block')
     ->set('unban_label', 'Unblock')
diff --git a/private_message.services.yml b/private_message.services.yml
index 97f8362d..825ceb4c 100644
--- a/private_message.services.yml
+++ b/private_message.services.yml
@@ -1,44 +1,35 @@
 services:
+
+  _defaults:
+    autoconfigure: true
+    autowire: true
+
   private_message.mapper:
     class: Drupal\private_message\Mapper\PrivateMessageMapper
-    arguments:
-      - '@database'
-      - '@current_user'
+  Drupal\private_message\Mapper\PrivateMessageMapperInterface: '@private_message.mapper'
 
   private_message.service:
     class: Drupal\private_message\Service\PrivateMessageService
-    arguments:
-      - '@private_message.mapper'
-      - '@current_user'
-      - '@config.factory'
-      - '@user.data'
-      - '@cache_tags.invalidator'
-      - '@entity_type.manager'
-      - '@datetime.time'
+  Drupal\private_message\Service\PrivateMessageServiceInterface: '@private_message.service'
 
   private_message.uninstaller:
     class: Drupal\private_message\Service\PrivateMessageUninstaller
+  Drupal\private_message\Service\PrivateMessageUninstallerInterface: '@private_message.uninstaller'
 
   private_message.ban_manager:
     class: Drupal\private_message\Service\PrivateMessageBanManager
-    arguments:
-      - '@current_user'
-      - '@entity_type.manager'
-      - '@database'
-      - '@messenger'
+  Drupal\private_message\Service\PrivateMessageBanManagerInterface: '@private_message.ban_manager'
 
   cache_context.private_message_thread:
     class: Drupal\private_message\Cache\Context\PrivateMessageThreadCacheContext
-    arguments:
-      - '@current_route_match'
     tags:
       - { name: cache.context }
 
   private_message.thread_manager:
     class: Drupal\private_message\Service\PrivateMessageThreadManager
-    arguments:
-      - '@private_message.service'
+  Drupal\private_message\Service\PrivateMessageThreadManagerInterface: '@private_message.thread_manager'
 
   private_message.private_message_config_form_manager:
     class: Drupal\private_message\PluginManager\PrivateMessageConfigFormManager
     parent: default_plugin_manager
+  Drupal\private_message\PluginManager\PrivateMessageConfigFormManagerInterface: '@private_message.private_message_config_form_manager'
diff --git a/src/Cache/Context/PrivateMessageThreadCacheContext.php b/src/Cache/Context/PrivateMessageThreadCacheContext.php
index a8f23f1e..b65f71ef 100644
--- a/src/Cache/Context/PrivateMessageThreadCacheContext.php
+++ b/src/Cache/Context/PrivateMessageThreadCacheContext.php
@@ -4,7 +4,7 @@ namespace Drupal\private_message\Cache\Context;
 
 use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Cache\Context\CacheContextInterface;
-use Drupal\Core\Routing\ResettableStackedRouteMatchInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
  * Defines the PrivateMessageThread service, for "per thread" caching.
@@ -13,22 +13,9 @@ use Drupal\Core\Routing\ResettableStackedRouteMatchInterface;
  */
 class PrivateMessageThreadCacheContext implements CacheContextInterface {
 
-  /**
-   * The current route matcher.
-   *
-   * @var \Drupal\Core\Routing\ResettableStackedRouteMatchInterface
-   */
-  protected $currentRouteMatcher;
-
-  /**
-   * Constructs a new UserCacheContextBase class.
-   *
-   * @param \Drupal\Core\Routing\ResettableStackedRouteMatchInterface $currentRouteMatcher
-   *   The current route matcher.
-   */
-  public function __construct(ResettableStackedRouteMatchInterface $currentRouteMatcher) {
-    $this->currentRouteMatcher = $currentRouteMatcher;
-  }
+  public function __construct(
+    protected readonly RouteMatchInterface $currentRouteMatch,
+  ) {}
 
   /**
    * {@inheritdoc}
@@ -40,10 +27,10 @@ class PrivateMessageThreadCacheContext implements CacheContextInterface {
   /**
    * {@inheritdoc}
    */
-  public function getContext() {
-    $thread = $this->currentRouteMatcher->getParameter('private_message_thread');
+  public function getContext(): string {
+    $thread = $this->currentRouteMatch->getParameter('private_message_thread');
     if ($thread) {
-      return $thread->id();
+      return (string) $thread->id();
     }
     return 'none';
   }
@@ -51,7 +38,7 @@ class PrivateMessageThreadCacheContext implements CacheContextInterface {
   /**
    * {@inheritdoc}
    */
-  public function getCacheableMetadata() {
+  public function getCacheableMetadata(): CacheableMetadata {
     return new CacheableMetadata();
   }
 
diff --git a/src/Controller/AjaxController.php b/src/Controller/AjaxController.php
index 0c825c0f..c8b70dd5 100644
--- a/src/Controller/AjaxController.php
+++ b/src/Controller/AjaxController.php
@@ -4,11 +4,8 @@ namespace Drupal\private_message\Controller;
 
 use Drupal\Core\Ajax\AjaxResponse;
 use Drupal\Core\Ajax\SettingsCommand;
-use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Controller\ControllerBase;
-use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Render\RendererInterface;
-use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\private_message\Ajax\PrivateMessageInboxInsertThreadsCommand;
 use Drupal\private_message\Ajax\PrivateMessageInboxUpdateCommand;
 use Drupal\private_message\Ajax\PrivateMessageInsertNewMessagesCommand;
@@ -16,7 +13,6 @@ use Drupal\private_message\Ajax\PrivateMessageInsertPreviousMessagesCommand;
 use Drupal\private_message\Ajax\PrivateMessageInsertThreadCommand;
 use Drupal\private_message\Ajax\PrivateMessageUpdateUnreadItemsCountCommand;
 use Drupal\private_message\Service\PrivateMessageServiceInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\RequestStack;
 
 /**
@@ -24,77 +20,11 @@ use Symfony\Component\HttpFoundation\RequestStack;
  */
 class AjaxController extends ControllerBase implements AjaxControllerInterface {
 
-  /**
-   * The renderer service.
-   *
-   * @var \Drupal\Core\Render\RendererInterface
-   */
-  protected $renderer;
-
-  /**
-   * The request stack.
-   *
-   * @var \Symfony\Component\HttpFoundation\RequestStack
-   */
-  protected $requestStack;
-
-  /**
-   * The entity manager service.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected $entityTypeManager;
-
-  /**
-   * The configuration factory.
-   *
-   * @var \Drupal\Core\Config\ConfigFactoryInterface
-   */
-  protected $configFactory;
-
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected $currentUser;
-
-  /**
-   * The private message service.
-   *
-   * @var \Drupal\private_message\Service\PrivateMessageServiceInterface
-   */
-  protected $privateMessageService;
-
   public function __construct(
-    RendererInterface $renderer,
-    RequestStack $requestStack,
-    EntityTypeManagerInterface $entityTypeManager,
-    ConfigFactoryInterface $configFactory,
-    AccountProxyInterface $currentUser,
-    PrivateMessageServiceInterface $privateMessageService,
-  ) {
-    $this->renderer = $renderer;
-    $this->requestStack = $requestStack;
-    $this->entityTypeManager = $entityTypeManager;
-    $this->configFactory = $configFactory;
-    $this->currentUser = $currentUser;
-    $this->privateMessageService = $privateMessageService;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('renderer'),
-      $container->get('request_stack'),
-      $container->get('entity_type.manager'),
-      $container->get('config.factory'),
-      $container->get('current_user'),
-      $container->get('private_message.service'),
-    );
-  }
+    protected readonly RendererInterface $renderer,
+    protected readonly RequestStack $requestStack,
+    protected readonly PrivateMessageServiceInterface $privateMessageService,
+  ) {}
 
   /**
    * {@inheritdoc}
@@ -155,7 +85,7 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface {
     $count = 0;
     if (is_numeric($thread_id) && is_numeric($message_id)) {
       /** @var \Drupal\private_message\Entity\PrivateMessageThreadInterface $thread */
-      $thread = $this->entityTypeManager
+      $thread = $this->entityTypeManager()
         ->getStorage('private_message_thread')
         ->load($thread_id);
       if ($thread) {
@@ -164,9 +94,9 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface {
         $count = count($new_messages);
         if ($count) {
           $messages = [];
-          $view_builder = $this->entityTypeManager->getViewBuilder('private_message');
+          $view_builder = $this->entityTypeManager()->getViewBuilder('private_message');
           foreach ($new_messages as $message) {
-            if ($message->access('view', $this->currentUser)) {
+            if ($message->access('view', $this->currentUser())) {
               $message_view = $view_builder->view($message);
               $message_view['#prefix'] = '<div class="private-message-wrapper field__item">';
               $message_view['#suffix'] = '</div>';
@@ -198,10 +128,10 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface {
 
       if (count($message_info['messages'])) {
         $messages = [];
-        $view_builder = $this->entityTypeManager->getViewBuilder('private_message');
+        $view_builder = $this->entityTypeManager()->getViewBuilder('private_message');
         $has_next = $message_info['next_exists'];
         foreach ($message_info['messages'] as $message) {
-          if ($message->access('view', $this->currentUser)) {
+          if ($message->access('view', $this->currentUser())) {
             $message_view = $view_builder->view($message);
             $message_view['#prefix'] = '<div class="private-message-wrapper field__item">';
             $message_view['#suffix'] = '</div>';
@@ -230,10 +160,10 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface {
       $thread_info = $this->privateMessageService->getThreadsForUser($thread_count, $timestamp);
       $has_next = FALSE;
       if (count($thread_info['threads'])) {
-        $view_builder = $this->entityTypeManager->getViewBuilder('private_message_thread');
+        $view_builder = $this->entityTypeManager()->getViewBuilder('private_message_thread');
         $threads = [];
         foreach ($thread_info['threads'] as $thread) {
-          if ($thread->access('view', $this->currentUser)) {
+          if ($thread->access('view', $this->currentUser())) {
             $has_next = $thread_info['next_exists'];
             $threads[] = $view_builder->view($thread, 'inbox');
           }
@@ -263,18 +193,19 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface {
     else {
       // No IDs were posted, so the maximum possible number of threads to be
       // returned is retrieved from the block settings.
-      $thread_count = $this->configFactory->get('block.block.privatemessageinbox')->get('settings.thread_count');
+      $thread_count = $this->config('block.block.privatemessageinbox')
+        ->get('settings.thread_count');
       $inbox_threads = $this->privateMessageService->getUpdatedInboxThreads([], $thread_count);
     }
 
     // Only need to do something if any thread IDS were found.
     if (count($inbox_threads['thread_ids'])) {
-      $view_builder = $this->entityTypeManager->getViewBuilder('private_message_thread');
+      $view_builder = $this->entityTypeManager()->getViewBuilder('private_message_thread');
 
       // Render any new threads as HTML to be sent to the browser.
       $rendered_threads = [];
       foreach (array_keys($inbox_threads['new_threads']) as $thread_id) {
-        if ($inbox_threads['new_threads'][$thread_id]->access('view', $this->currentUser)) {
+        if ($inbox_threads['new_threads'][$thread_id]->access('view', $this->currentUser())) {
           $renderable = $view_builder->view($inbox_threads['new_threads'][$thread_id], 'inbox');
           $rendered_threads[$thread_id] = $this->renderer->renderRoot($renderable);
         }
@@ -324,12 +255,12 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface {
   protected function loadThread(AjaxResponse $response) {
     $thread_id = $this->requestStack->getCurrentRequest()->get('id');
     if ($thread_id) {
-      $thread = $this->entityTypeManager->getStorage('private_message_thread')->load($thread_id);
+      $thread = $this->entityTypeManager()->getStorage('private_message_thread')->load($thread_id);
 
-      if ($thread && $thread->access('view', $this->currentUser)) {
+      if ($thread && $thread->access('view', $this->currentUser())) {
         $this->privateMessageService->updateLastCheckTime();
 
-        $view_builder = $this->entityTypeManager->getViewBuilder('private_message_thread');
+        $view_builder = $this->entityTypeManager()->getViewBuilder('private_message_thread');
         $renderable = $view_builder->view($thread);
         $rendered_thread = $this->renderer->renderRoot($renderable);
 
diff --git a/src/Controller/PrivateMessageController.php b/src/Controller/PrivateMessageController.php
index 5ddb07da..d7a8c459 100644
--- a/src/Controller/PrivateMessageController.php
+++ b/src/Controller/PrivateMessageController.php
@@ -2,103 +2,22 @@
 
 namespace Drupal\private_message\Controller;
 
-use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Controller\ControllerBase;
-use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Form\FormBuilderInterface;
 use Drupal\Core\Link;
-use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\Core\Url;
 use Drupal\private_message\Form\BanUserForm;
 use Drupal\private_message\Service\PrivateMessageServiceInterface;
 use Drupal\user\UserDataInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Private message page controller. Returns render arrays for the page.
  */
 class PrivateMessageController extends ControllerBase implements PrivateMessageControllerInterface {
 
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected $currentUser;
-
-  /**
-   * The entity manager service.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected $entityTypeManager;
-
-  /**
-   * The form builder interface.
-   *
-   * @var \Drupal\Core\Form\FormBuilderInterface
-   */
-  protected $formBuilder;
-
-  /**
-   * The user data service.
-   *
-   * @var \Drupal\user\UserDataInterface
-   */
-  protected $userData;
-
-  /**
-   * The private message service.
-   *
-   * @var \Drupal\private_message\Service\PrivateMessageServiceInterface
-   */
-  protected $privateMessageService;
-
-  /**
-   * The configuration factory service.
-   *
-   * @var \Drupal\Core\Config\ImmutableConfig
-   */
-  protected $config;
-
-  /**
-   * Constructs a PrivateMessageForm object.
-   *
-   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
-   *   The current user.
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
-   *   The entity manager service.
-   * @param \Drupal\Core\Form\FormBuilderInterface $formBuilder
-   *   The form builder service.
-   * @param \Drupal\user\UserDataInterface $userData
-   *   The user data service.
-   * @param \Drupal\private_message\Service\PrivateMessageServiceInterface $privateMessageService
-   *   The private message service.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
-   *   The config factory service.
-   */
-  public function __construct(AccountProxyInterface $currentUser, EntityTypeManagerInterface $entityTypeManager, FormBuilderInterface $formBuilder, UserDataInterface $userData, PrivateMessageServiceInterface $privateMessageService, ConfigFactoryInterface $configFactory) {
-    $this->currentUser = $currentUser;
-    $this->entityTypeManager = $entityTypeManager;
-    $this->formBuilder = $formBuilder;
-    $this->userData = $userData;
-    $this->privateMessageService = $privateMessageService;
-    $this->config = $configFactory->get('private_message.settings');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('current_user'),
-      $container->get('entity_type.manager'),
-      $container->get('form_builder'),
-      $container->get('user.data'),
-      $container->get('private_message.service'),
-      $container->get('config.factory')
-    );
-  }
+  public function __construct(
+    protected readonly UserDataInterface $userData,
+    protected readonly PrivateMessageServiceInterface $privateMessageService,
+  ) {}
 
   /**
    * {@inheritdoc}
@@ -107,14 +26,14 @@ class PrivateMessageController extends ControllerBase implements PrivateMessageC
     $this->privateMessageService->updateLastCheckTime();
 
     /** @var \Drupal\user\UserInterface $user */
-    $user = $this->entityTypeManager
+    $user = $this->entityTypeManager()
       ->getStorage('user')
-      ->load($this->currentUser->id());
+      ->load($this->currentUser()->id());
 
     $private_message_thread = $this->privateMessageService->getFirstThreadForUser($user);
 
     if ($private_message_thread) {
-      $view_builder = $this->entityTypeManager->getViewBuilder('private_message_thread');
+      $view_builder = $this->entityTypeManager()->getViewBuilder('private_message_thread');
       // No wrapper is provided, as the full view mode of the entity already
       // provides the #private-message-page wrapper.
       $page = $view_builder->view($private_message_thread);
@@ -161,7 +80,7 @@ class PrivateMessageController extends ControllerBase implements PrivateMessageC
     return [
       '#prefix' => '<div id="private_message_configuration_page">',
       '#suffix' => '</div>',
-      'form' => $this->formBuilder->getForm('Drupal\private_message\Form\ConfigForm'),
+      'form' => $this->formBuilder()->getForm('Drupal\private_message\Form\ConfigForm'),
     ];
   }
 
@@ -190,8 +109,8 @@ class PrivateMessageController extends ControllerBase implements PrivateMessageC
    * {@inheritdoc}
    */
   public function banUnbanPage(): array {
-    $user_has_permission = $this->currentUser->hasPermission('use private messaging system')
-      && $this->currentUser->hasPermission('access user profiles');
+    $user_has_permission = $this->currentUser()->hasPermission('use private messaging system')
+      && $this->currentUser()->hasPermission('access user profiles');
 
     $table = [];
 
@@ -200,13 +119,13 @@ class PrivateMessageController extends ControllerBase implements PrivateMessageC
       $header = [t('User'), t('Operations')];
 
       /** @var \Drupal\private_message\Entity\PrivateMessageBan[] $private_message_bans */
-      $private_message_bans = $this->entityTypeManager
+      $private_message_bans = $this->entityTypeManager()
         ->getStorage('private_message_ban')
-        ->loadByProperties(['owner' => $this->currentUser->id()]);
+        ->loadByProperties(['owner' => $this->currentUser()->id()]);
 
       $destination = Url::fromRoute('<current>')->getInternalPath();
       foreach ($private_message_bans as $private_message_ban) {
-        $label = $this->config->get('unban_label');
+        $label = $this->config('private_message.settings')->get('unban_label');
         $url = Url::fromRoute('private_message.unban_user_form',
           ['user' => $private_message_ban->getTargetId()],
           ['query' => ['destination' => $destination]],
@@ -230,7 +149,7 @@ class PrivateMessageController extends ControllerBase implements PrivateMessageC
       'content' => [
         $table,
         [
-          'form' => $this->formBuilder->getForm(BanUserForm::class),
+          'form' => $this->formBuilder()->getForm(BanUserForm::class),
         ],
       ],
     ];
diff --git a/src/Drush/Commands/PrivateMessageCommands.php b/src/Drush/Commands/PrivateMessageCommands.php
index fab16479..868fa999 100644
--- a/src/Drush/Commands/PrivateMessageCommands.php
+++ b/src/Drush/Commands/PrivateMessageCommands.php
@@ -2,7 +2,7 @@
 
 namespace Drupal\private_message\Drush\Commands;
 
-use Drupal\Component\DependencyInjection\ContainerInterface;
+use Drupal\Core\DependencyInjection\AutowireTrait;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\private_message\Service\PrivateMessageUninstallerInterface;
 use Drush\Attributes as CLI;
@@ -13,6 +13,7 @@ use Drush\Commands\DrushCommands;
  */
 final class PrivateMessageCommands extends DrushCommands {
 
+  use AutowireTrait;
   use StringTranslationTrait;
 
   public function __construct(
@@ -21,15 +22,6 @@ final class PrivateMessageCommands extends DrushCommands {
     parent::__construct();
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container): self {
-    return new static(
-      $container->get('private_message.uninstaller')
-    );
-  }
-
   /**
    * Prepares the Private Message module for uninstallation.
    */
diff --git a/src/Form/BanUserForm.php b/src/Form/BanUserForm.php
index 6e1ebadf..fe585c1c 100644
--- a/src/Form/BanUserForm.php
+++ b/src/Form/BanUserForm.php
@@ -2,82 +2,23 @@
 
 namespace Drupal\private_message\Form;
 
-use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\DependencyInjection\AutowireTrait;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\private_message\Service\PrivateMessageBanManagerInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Private Message users banning form.
  */
 class BanUserForm extends FormBase {
 
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected AccountProxyInterface $currentUser;
-
-  /**
-   * The entity type manager service.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected EntityTypeManagerInterface $entityTypeManager;
+  use AutowireTrait;
 
-  /**
-   * The private message configuration.
-   *
-   * @var \Drupal\Core\Config\ConfigFactoryInterface
-   */
-  protected $configFactory;
-
-  /**
-   * The Private Message Ban manager.
-   *
-   * @var \Drupal\private_message\Service\PrivateMessageBanManagerInterface
-   */
-  private PrivateMessageBanManagerInterface $privateMessageBanManager;
-
-  /**
-   * Constructs a BanUserForm object.
-   *
-   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
-   *   The current user.
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
-   *   The entity type manager service.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
-   *   The configuration factory service.
-   * @param \Drupal\private_message\Service\PrivateMessageBanManagerInterface $privateMessageBanManager
-   *   The Private Message Ban manager.
-   */
   public function __construct(
-    AccountProxyInterface $currentUser,
-    EntityTypeManagerInterface $entityTypeManager,
-    ConfigFactoryInterface $configFactory,
-    PrivateMessageBanManagerInterface $privateMessageBanManager,
-  ) {
-    $this->currentUser = $currentUser;
-    $this->entityTypeManager = $entityTypeManager;
-    $this->configFactory = $configFactory;
-    $this->privateMessageBanManager = $privateMessageBanManager;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container): self {
-    return new static(
-      $container->get('current_user'),
-      $container->get('entity_type.manager'),
-      $container->get('config.factory'),
-      $container->get('private_message.ban_manager'),
-    );
-  }
+    protected readonly EntityTypeManagerInterface $entityTypeManager,
+    protected readonly PrivateMessageBanManagerInterface $privateMessageBanManager,
+  ) {}
 
   /**
    * {@inheritdoc}
@@ -90,7 +31,7 @@ class BanUserForm extends FormBase {
    * {@inheritdoc}
    */
   public function buildForm(array $form, FormStateInterface $form_state): array {
-    $config = $this->configFactory->get('private_message.settings');
+    $config = $this->config('private_message.settings');
 
     $form['banned_user'] = [
       '#title' => $this->t('Select User'),
@@ -118,7 +59,7 @@ class BanUserForm extends FormBase {
   public function validateForm(array &$form, FormStateInterface $form_state): void {
     $userId = $form_state->getValue('banned_user');
     // Add security to prevent blocking ourselves.
-    if ($userId === $this->currentUser->id()) {
+    if ($userId === $this->currentUser()->id()) {
       $form_state->setErrorByName($userId, $this->t("You can't block yourself."));
     }
 
diff --git a/src/Form/ConfigForm.php b/src/Form/ConfigForm.php
index 1993bdce..54178e80 100644
--- a/src/Form/ConfigForm.php
+++ b/src/Form/ConfigForm.php
@@ -4,49 +4,47 @@ namespace Drupal\private_message\Form;
 
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Config\TypedConfigManagerInterface;
+use Drupal\Core\DependencyInjection\AutowireTrait;
 use Drupal\Core\Form\ConfigFormBase;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\private_message\PluginManager\PrivateMessageConfigFormManager;
-use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\private_message\Model\BlockType;
+use Drupal\private_message\PluginManager\PrivateMessageConfigFormManagerInterface;
 
 /**
  * Defines the configuration form for the private message module.
  */
 class ConfigForm extends ConfigFormBase {
 
+  use AutowireTrait;
+
   /**
-   * Ban types.
+   * Blocking type: passive.
+   *
+   * @deprecated in private_message:4.0.0 and is removed from
+   * private_message:5.0.0. Use \Drupal\private_message\Model\BlockType::Passive
+   * instead.
    *
-   * @todo Move to Enum.
+   * @see https://www.drupal.org/project/private_message/issues/3490037
    */
   const PASSIVE = 'passive';
-  const ACTIVE = 'active';
 
   /**
-   * The private message config form plugin manager.
+   * Blocking type: active.
    *
-   * @var \Drupal\private_message\PluginManager\PrivateMessageConfigFormManager
+   * @deprecated in private_message:4.0.0 and is removed from
+   * private_message:5.0.0. Use \Drupal\private_message\Model\BlockType::Active
+   * instead.
+   *
+   * @see https://www.drupal.org/project/private_message/issues/3490037
    */
-  protected $privateMessageConfigFormManager;
+  const ACTIVE = 'active';
 
   public function __construct(
     ConfigFactoryInterface $configFactory,
     TypedConfigManagerInterface $typedConfigManager,
-    PrivateMessageConfigFormManager $privateMessageConfigFormManager,
+    protected readonly PrivateMessageConfigFormManagerInterface $privateMessageConfigFormManager,
   ) {
     parent::__construct($configFactory, $typedConfigManager);
-    $this->privateMessageConfigFormManager = $privateMessageConfigFormManager;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('config.factory'),
-      $container->get('config.typed'),
-      $container->get('private_message.private_message_config_form_manager')
-    );
   }
 
   /**
@@ -185,17 +183,12 @@ class ConfigForm extends ConfigFormBase {
     $form['pm_block']['ban_mode'] = [
       '#type' => 'radios',
       '#title' => $this->t("Blocking mode"),
-      '#default_value' => $config->get('ban_mode') ?: self::PASSIVE,
-      '#options' => [
-        self::PASSIVE => $this
-          ->t('Passive'),
-        self::ACTIVE => $this
-          ->t('Active'),
-      ],
-      self::PASSIVE => [
+      '#default_value' => $config->get('ban_mode') ?: BlockType::Passive->value,
+      '#options' => BlockType::asOptions(),
+      BlockType::Passive->value => [
         '#description' => $this->t('Blocked members do not know they are blocked and can message the user that blocked them. The user who blocked them will not see the message.'),
       ],
-      self::ACTIVE => [
+      BlockType::Active->value => [
         '#description' => $this->t('Blocked members cannot message users that blocked them and instead a message is shown.'),
       ],
     ];
diff --git a/src/Form/ConfirmBanUserForm.php b/src/Form/ConfirmBanUserForm.php
index 456520b4..1da4c1a2 100644
--- a/src/Form/ConfirmBanUserForm.php
+++ b/src/Form/ConfirmBanUserForm.php
@@ -2,78 +2,33 @@
 
 namespace Drupal\private_message\Form;
 
+use Drupal\Core\DependencyInjection\AutowireTrait;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\Core\Url;
+use Drupal\private_message\Model\BlockType;
 use Drupal\private_message\Service\PrivateMessageBanManagerInterface;
 use Drupal\user\UserInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * The User Ban confirmation form.
  */
 class ConfirmBanUserForm extends ConfirmFormBase {
 
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected AccountProxyInterface $currentUser;
-
-  /**
-   * The entity type manager service.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected EntityTypeManagerInterface $entityTypeManager;
-
-  /**
-   * The Private Message Ban manager.
-   *
-   * @var \Drupal\private_message\Service\PrivateMessageBanManagerInterface
-   */
-  protected PrivateMessageBanManagerInterface $privateMessageBanManager;
+  use AutowireTrait;
 
   /**
    * The user to block.
-   *
-   * @var \Drupal\user\UserInterface|null
    */
   protected ?UserInterface $user;
 
-  /**
-   * Constructs a ConfirmBanUserForm object.
-   *
-   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
-   *   The current user.
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
-   *   The entity type manager service.
-   * @param \Drupal\private_message\Service\PrivateMessageBanManagerInterface $privateMessageBanManager
-   *   The Private Message Ban manager.
-   */
   public function __construct(
-    AccountProxyInterface $currentUser,
-    EntityTypeManagerInterface $entityTypeManager,
-    PrivateMessageBanManagerInterface $privateMessageBanManager,
-  ) {
-    $this->currentUser = $currentUser;
-    $this->entityTypeManager = $entityTypeManager;
-    $this->privateMessageBanManager = $privateMessageBanManager;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('current_user'),
-      $container->get('entity_type.manager'),
-      $container->get('private_message.ban_manager'),
-    );
-  }
+    protected readonly AccountProxyInterface $currentUser,
+    protected readonly EntityTypeManagerInterface $entityTypeManager,
+    protected readonly PrivateMessageBanManagerInterface $privateMessageBanManager,
+  ) {}
 
   /**
    * {@inheritdoc}
@@ -145,7 +100,7 @@ class ConfirmBanUserForm extends ConfirmFormBase {
   public function getDescription() {
     $config = $this->config('private_message.settings');
 
-    if ($config->get('ban_mode') == ConfigForm::PASSIVE) {
+    if ($config->get('ban_mode') === BlockType::Passive->value) {
       return $this->t('By confirming, you will no longer be able to send messages to this user.');
     }
     else {
diff --git a/src/Form/ConfirmUnbanUserForm.php b/src/Form/ConfirmUnbanUserForm.php
index 5fdd7323..46389676 100644
--- a/src/Form/ConfirmUnbanUserForm.php
+++ b/src/Form/ConfirmUnbanUserForm.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\private_message\Form;
 
+use Drupal\Core\DependencyInjection\AutowireTrait;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
@@ -9,71 +10,24 @@ use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\Core\Url;
 use Drupal\private_message\Service\PrivateMessageBanManagerInterface;
 use Drupal\user\UserInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * User unban confirmation form.
  */
 class ConfirmUnbanUserForm extends ConfirmFormBase {
 
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected AccountProxyInterface $currentUser;
-
-  /**
-   * The entity type manager service.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected EntityTypeManagerInterface $entityTypeManager;
-
-  /**
-   * The Private Message Ban manager.
-   *
-   * @var \Drupal\private_message\Service\PrivateMessageBanManagerInterface
-   */
-  private PrivateMessageBanManagerInterface $privateMessageBanManager;
+  use AutowireTrait;
 
   /**
    * The user to unban.
-   *
-   * @var \Drupal\user\UserInterface|null
    */
   private ?UserInterface $user;
 
-  /**
-   * Constructs a BlockUserForm object.
-   *
-   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
-   *   The current user.
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
-   *   The entity type manager service.
-   * @param \Drupal\private_message\Service\PrivateMessageBanManagerInterface $privateMessageBanManager
-   *   The Private Message Ban manager.
-   */
   public function __construct(
-    AccountProxyInterface $currentUser,
-    EntityTypeManagerInterface $entityTypeManager,
-    PrivateMessageBanManagerInterface $privateMessageBanManager,
-  ) {
-    $this->currentUser = $currentUser;
-    $this->entityTypeManager = $entityTypeManager;
-    $this->privateMessageBanManager = $privateMessageBanManager;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('current_user'),
-      $container->get('entity_type.manager'),
-      $container->get('private_message.ban_manager'),
-    );
-  }
+    protected readonly AccountProxyInterface $currentUser,
+    protected readonly EntityTypeManagerInterface $entityTypeManager,
+    protected readonly PrivateMessageBanManagerInterface $privateMessageBanManager,
+  ) {}
 
   /**
    * {@inheritdoc}
diff --git a/src/Form/PrivateMessageForm.php b/src/Form/PrivateMessageForm.php
index 6b36b39b..a0307414 100644
--- a/src/Form/PrivateMessageForm.php
+++ b/src/Form/PrivateMessageForm.php
@@ -7,36 +7,37 @@ use Drupal\Component\Utility\Html;
 use Drupal\Core\Ajax\AjaxResponse;
 use Drupal\Core\Ajax\ReplaceCommand;
 use Drupal\Core\Config\ConfigFactoryInterface;
-use Drupal\Core\Config\ImmutableConfig;
+use Drupal\Core\DependencyInjection\AutowireTrait;
 use Drupal\Core\Entity\ContentEntityForm;
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
 use Drupal\Core\Entity\EntityRepositoryInterface;
 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
-use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
 use Drupal\Core\Form\FormBuilderInterface;
 use Drupal\Core\Form\FormState;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element\StatusMessages;
-use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\Core\TypedData\TypedDataManagerInterface;
 use Drupal\private_message\Ajax\PrivateMessageInboxTriggerUpdateCommand;
 use Drupal\private_message\Ajax\PrivateMessageLoadNewMessagesCommand;
 use Drupal\private_message\Entity\PrivateMessage;
 use Drupal\private_message\Entity\PrivateMessageThread;
 use Drupal\private_message\Entity\PrivateMessageThreadInterface;
+use Drupal\private_message\Model\BlockType;
 use Drupal\private_message\Service\PrivateMessageBanManagerInterface;
 use Drupal\private_message\Service\PrivateMessageServiceInterface;
 use Drupal\private_message\Service\PrivateMessageThreadManagerInterface;
-use Drupal\user\UserDataInterface;
+use Drupal\private_message\Traits\PrivateMessageSettingsTrait;
 use Drupal\user\UserInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Defines the private message form.
  */
 class PrivateMessageForm extends ContentEntityForm {
 
+  use AutowireTrait;
+  use PrivateMessageSettingsTrait;
+
   /**
    * A unique instance identifier for the form.
    *
@@ -44,141 +45,19 @@ class PrivateMessageForm extends ContentEntityForm {
    */
   protected $formId;
 
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected $currentUser;
-
-  /**
-   * The entity type manager service.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected $entityTypeManager;
-
-  /**
-   * The typed data manager service.
-   *
-   * @var \Drupal\Core\TypedData\TypedDataManagerInterface
-   */
-  protected $typedDataManager;
-
-  /**
-   * The user data service.
-   *
-   * @var \Drupal\user\UserDataInterface
-   */
-  protected $userData;
-
-  /**
-   * The private message service.
-   *
-   * @var \Drupal\private_message\Service\PrivateMessageServiceInterface
-   */
-  protected $privateMessageService;
-
-  /**
-   * The private message thread manager service.
-   *
-   * @var \Drupal\private_message\Service\PrivateMessageThreadManagerInterface
-   */
-  protected $privateMessageThreadManager;
-
-  /**
-   * The Private Message Ban manager.
-   *
-   * @var \Drupal\private_message\Service\PrivateMessageBanManagerInterface
-   */
-  protected PrivateMessageBanManagerInterface $privateMessageBanManager;
-
-  /**
-   * The Form Builder service.
-   *
-   * @var \Drupal\Core\Form\FormBuilderInterface
-   */
-  protected $formBuilder;
-
-  /**
-   * The message configuration.
-   *
-   * @var \Drupal\Core\Config\ImmutableConfig
-   */
-  protected ImmutableConfig $config;
-
-  /**
-   * Constructs a PrivateMessageForm object.
-   *
-   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entityRepository
-   *   The entity repository service.
-   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
-   *   The entity type bundle service.
-   * @param \Drupal\Component\Datetime\TimeInterface $time
-   *   The time service.
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
-   *   The entity type manager service.
-   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
-   *   The current user.
-   * @param \Drupal\Core\TypedData\TypedDataManagerInterface $typedDataManager
-   *   The typed data manager service.
-   * @param \Drupal\user\UserDataInterface $userData
-   *   The user data service.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
-   *   The configuration factory service.
-   * @param \Drupal\private_message\Service\PrivateMessageServiceInterface $privateMessageService
-   *   The private message service.
-   * @param \Drupal\private_message\Service\PrivateMessageThreadManagerInterface $privateMessageThreadManager
-   *   The private message thread manager service.
-   * @param \Drupal\private_message\Service\PrivateMessageBanManagerInterface $privateMessageBanManager
-   *   The Private Message Ban manager.
-   * @param \Drupal\Core\Form\FormBuilderInterface $formBuilder
-   *   The Form Builder service.
-   */
   public function __construct(
     EntityRepositoryInterface $entityRepository,
     EntityTypeBundleInfoInterface $entity_type_bundle_info,
     TimeInterface $time,
-    EntityTypeManagerInterface $entityTypeManager,
-    AccountProxyInterface $currentUser,
-    TypedDataManagerInterface $typedDataManager,
-    UserDataInterface $userData,
     ConfigFactoryInterface $configFactory,
-    PrivateMessageServiceInterface $privateMessageService,
-    PrivateMessageThreadManagerInterface $privateMessageThreadManager,
-    PrivateMessageBanManagerInterface $privateMessageBanManager,
-    FormBuilderInterface $formBuilder,
+    protected readonly TypedDataManagerInterface $typedDataManager,
+    protected readonly PrivateMessageServiceInterface $privateMessageService,
+    protected readonly PrivateMessageThreadManagerInterface $privateMessageThreadManager,
+    protected readonly PrivateMessageBanManagerInterface $privateMessageBanManager,
+    protected readonly FormBuilderInterface $formBuilder,
   ) {
     parent::__construct($entityRepository, $entity_type_bundle_info, $time);
-    $this->entityTypeManager = $entityTypeManager;
-    $this->currentUser = $currentUser;
-    $this->typedDataManager = $typedDataManager;
-    $this->userData = $userData;
-    $this->config = $configFactory->get('private_message.settings');
-    $this->privateMessageService = $privateMessageService;
-    $this->privateMessageThreadManager = $privateMessageThreadManager;
-    $this->privateMessageBanManager = $privateMessageBanManager;
-    $this->formBuilder = $formBuilder;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('entity.repository'),
-      $container->get('entity_type.bundle.info'),
-      $container->get('datetime.time'),
-      $container->get('entity_type.manager'),
-      $container->get('current_user'),
-      $container->get('typed_data_manager'),
-      $container->get('user.data'),
-      $container->get('config.factory'),
-      $container->get('private_message.service'),
-      $container->get('private_message.thread_manager'),
-      $container->get('private_message.ban_manager'),
-      $container->get('form_builder'),
-    );
+    $this->configFactory = $configFactory;
   }
 
   /**
@@ -215,15 +94,15 @@ class PrivateMessageForm extends ContentEntityForm {
     if ($privateMessageThread) {
 
       $threadMembers = $privateMessageThread->getMembersId();
-      $bannedUsers = $this->privateMessageBanManager->getBannedUsers($this->currentUser->id());
+      $bannedUsers = $this->privateMessageBanManager->getBannedUsers($this->currentUser()->id());
 
       $banned = FALSE;
       foreach ($bannedUsers as $bannedUser) {
         if (\in_array($bannedUser, $threadMembers)) {
 
-          if (!empty($this->config->get('ban_message'))) {
+          if (!empty($this->getSettings()->get('ban_message'))) {
             $this->messenger()
-              ->addError($this->config->get('ban_message'));
+              ->addError($this->getSettings()->get('ban_message'));
 
             $form['message_for_user'] = [
               StatusMessages::renderMessages(),
@@ -239,16 +118,16 @@ class PrivateMessageForm extends ContentEntityForm {
 
       // Block messaging form for active blocking mode.
       if (!$banned) {
-        $ban_mode = $this->config->get('ban_mode');
-        if ($ban_mode === ConfigForm::ACTIVE) {
+        $ban_mode = $this->getSettings()->get('ban_mode');
+        if ($ban_mode === BlockType::Active) {
 
           foreach ($threadMembers as $threadMember) {
             $bannedUsers = $this->privateMessageBanManager->getBannedUsers($threadMember);
-            if (in_array($this->currentUser->id(), $bannedUsers)) {
+            if (in_array($this->currentUser()->id(), $bannedUsers)) {
 
-              if (!empty($this->config->get('ban_message'))) {
+              if (!empty($this->getSettings()->get('ban_message'))) {
                 $this->messenger()
-                  ->addError($this->config->get('ban_message'));
+                  ->addError($this->getSettings()->get('ban_message'));
 
                 $form['message_for_user'] = [
                   StatusMessages::renderMessages(),
@@ -272,8 +151,8 @@ class PrivateMessageForm extends ContentEntityForm {
 
         // Only to do these when using #ajax.
         $form['#attached']['library'][] = 'private_message/message_form';
-        $form['#attached']['drupalSettings']['privateMessageSendKey'] = $this->config->get('keys_send');
-        $autofocus_enabled = $this->config->get('autofocus_enable');
+        $form['#attached']['drupalSettings']['privateMessageSendKey'] = $this->getSettings()->get('keys_send');
+        $autofocus_enabled = $this->getSettings()->get('autofocus_enable');
         if ($autofocus_enabled) {
           $form['message']['widget'][0]['#attributes']['autofocus'] = 'autofocus';
         }
@@ -311,7 +190,7 @@ class PrivateMessageForm extends ContentEntityForm {
 
     $form['#validate'][] = '::validateBannedMembers';
 
-    if ($save_label = $this->config->get('save_message_label')) {
+    if ($save_label = $this->getSettings()->get('save_message_label')) {
       $form['actions']['submit']['#value'] = $save_label;
     }
 
@@ -367,7 +246,7 @@ class PrivateMessageForm extends ContentEntityForm {
       }
     }
 
-    if ((count($members) === 1 && $this->currentUser->id() === $members[0]->id())) {
+    if ((count($members) === 1 && $this->currentUser()->id() === $members[0]->id())) {
       $formState->setError($form['members'], $this->t('You can not send a message to yourself only.'));
     }
 
@@ -398,7 +277,7 @@ class PrivateMessageForm extends ContentEntityForm {
     /** @var \Drupal\private_message\Entity\PrivateMessageThread|null $privateMessageThread */
     $privateMessageThread = $formState->get('thread');
     $threadMembers = $privateMessageThread ? $privateMessageThread->getMembersId() : [];
-    $bannedUsers = $this->privateMessageBanManager->getBannedUsers($this->currentUser->id());
+    $bannedUsers = $this->privateMessageBanManager->getBannedUsers($this->currentUser()->id());
 
     foreach ($bannedUsers as $bannedUser) {
       if (in_array($bannedUser, $threadMembers)) {
@@ -486,7 +365,7 @@ class PrivateMessageForm extends ContentEntityForm {
       // Generate an array containing the members of the thread.
       $current_user = $this->entityTypeManager
         ->getStorage('user')
-        ->load($this->currentUser->id());
+        ->load($this->currentUser()->id());
 
       $members = [$current_user];
 
diff --git a/src/Mapper/PrivateMessageMapper.php b/src/Mapper/PrivateMessageMapper.php
index 3b085b9a..68ace052 100644
--- a/src/Mapper/PrivateMessageMapper.php
+++ b/src/Mapper/PrivateMessageMapper.php
@@ -13,32 +13,10 @@ use Drupal\user\UserInterface;
  */
 class PrivateMessageMapper implements PrivateMessageMapperInterface {
 
-  /**
-   * The database connection.
-   *
-   * @var \Drupal\Core\Database\Connection
-   */
-  protected Connection $database;
-
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected AccountProxyInterface $currentUser;
-
-  /**
-   * Constructs a PrivateMessageMapper object.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
-   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
-   *   The current user.
-   */
-  public function __construct(Connection $database, AccountProxyInterface $currentUser) {
-    $this->database = $database;
-    $this->currentUser = $currentUser;
-  }
+  public function __construct(
+    protected readonly Connection $database,
+    protected readonly AccountProxyInterface $currentUser,
+  ) {}
 
   /**
    * {@inheritdoc}
diff --git a/src/Model/BlockType.php b/src/Model/BlockType.php
new file mode 100644
index 00000000..e4abd195
--- /dev/null
+++ b/src/Model/BlockType.php
@@ -0,0 +1,28 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\private_message\Model;
+
+/**
+ * Blocking type.
+ */
+enum BlockType: string {
+
+  case Passive = 'passive';
+  case Active = 'active';
+
+  /**
+   * Returns the enum as options.
+   *
+   * @return array
+   *   Options.
+   */
+  public static function asOptions(): array {
+    return [
+      self::Passive->value => t('Passive'),
+      self::Active->value => t('Active'),
+    ];
+  }
+
+}
diff --git a/src/PluginManager/PrivateMessageConfigFormManager.php b/src/PluginManager/PrivateMessageConfigFormManager.php
index 8c93ed9e..19582c19 100644
--- a/src/PluginManager/PrivateMessageConfigFormManager.php
+++ b/src/PluginManager/PrivateMessageConfigFormManager.php
@@ -1,29 +1,22 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\PluginManager;
 
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\private_message\Annotation\PrivateMessageConfigForm;
+use Drupal\private_message\Plugin\PrivateMessageConfigForm\PrivateMessageConfigFormPluginInterface;
 
 /**
- * Plugin Manager to detect PrivateMessageConfigForm plugins.
+ * Plugin manager for detect PrivateMessageConfigForm plugins.
  */
 class PrivateMessageConfigFormManager extends DefaultPluginManager implements PrivateMessageConfigFormManagerInterface {
 
-  /**
-   * Constructs a PrivateMessageConfigFormManager object.
-   *
-   * @param \Traversable $namespaces
-   *   Namespaces to be searched for the plugin.
-   * @param \Drupal\Core\Cache\CacheBackendInterface $cacheBackend
-   *   The cache backend.
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler
-   *   The module handler service.
-   */
   public function __construct(\Traversable $namespaces, CacheBackendInterface $cacheBackend, ModuleHandlerInterface $moduleHandler) {
-    parent::__construct('Plugin/PrivateMessageConfigForm', $namespaces, $moduleHandler, 'Drupal\private_message\Plugin\PrivateMessageConfigForm\PrivateMessageConfigFormPluginInterface', 'Drupal\private_message\Annotation\PrivateMessageConfigForm');
-
+    parent::__construct('Plugin/PrivateMessageConfigForm', $namespaces, $moduleHandler, PrivateMessageConfigFormPluginInterface::class, PrivateMessageConfigForm::class);
     $this->alterInfo('private_message_config_form_info');
     $this->setCacheBackend($cacheBackend, 'private_message_config_form');
   }
diff --git a/src/Service/PrivateMessageBanManager.php b/src/Service/PrivateMessageBanManager.php
index 589a379f..4a9503f5 100644
--- a/src/Service/PrivateMessageBanManager.php
+++ b/src/Service/PrivateMessageBanManager.php
@@ -4,7 +4,6 @@ namespace Drupal\private_message\Service;
 
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\private_message\Entity\PrivateMessageBanInterface;
@@ -16,57 +15,11 @@ class PrivateMessageBanManager implements PrivateMessageBanManagerInterface {
 
   use StringTranslationTrait;
 
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected AccountProxyInterface $currentUser;
-
-  /**
-   * The entity type manager.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected $entityTypeManager;
-
-  /**
-   * The database.
-   *
-   * @var \Drupal\Core\Database\Connection
-   */
-  private Connection $database;
-
-  /**
-   * The messenger service.
-   *
-   * @var \Drupal\Core\Messenger\MessengerInterface
-   */
-  private MessengerInterface $messenger;
-
-  /**
-   * Constructs a PrivateMessageBanManager object.
-   *
-   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
-   *   The current user.
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
-   *   The entity type manager interface.
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database.
-   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
-   *   The messenger service.
-   */
   public function __construct(
-    AccountProxyInterface $currentUser,
-    EntityTypeManagerInterface $entityTypeManager,
-    Connection $database,
-    MessengerInterface $messenger,
-  ) {
-    $this->currentUser = $currentUser;
-    $this->entityTypeManager = $entityTypeManager;
-    $this->database = $database;
-    $this->messenger = $messenger;
-  }
+    protected readonly AccountProxyInterface $currentUser,
+    protected readonly EntityTypeManagerInterface $entityTypeManager,
+    protected readonly Connection $database,
+  ) {}
 
   /**
    * {@inheritdoc}
diff --git a/src/Service/PrivateMessageService.php b/src/Service/PrivateMessageService.php
index ce0464c9..17c2d4f5 100644
--- a/src/Service/PrivateMessageService.php
+++ b/src/Service/PrivateMessageService.php
@@ -21,90 +21,15 @@ use Drupal\user\UserInterface;
  */
 class PrivateMessageService implements PrivateMessageServiceInterface {
 
-  /**
-   * The private message mapper service.
-   *
-   * @var \Drupal\private_message\Mapper\PrivateMessageMapperInterface
-   */
-  protected PrivateMessageMapperInterface $mapper;
-
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected AccountProxyInterface $currentUser;
-
-  /**
-   * The configuration factory.
-   *
-   * @var \Drupal\Core\Config\ConfigFactoryInterface
-   */
-  protected ConfigFactoryInterface $configFactory;
-
-  /**
-   * The user data service.
-   *
-   * @var \Drupal\user\UserDataInterface
-   */
-  protected UserDataInterface $userData;
-
-  /**
-   * Cache Tags Invalidator.
-   *
-   * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface
-   */
-  protected CacheTagsInvalidatorInterface $cacheTagsInvalidator;
-
-  /**
-   * The entity type manager.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected $entityTypeManager;
-
-  /**
-   * The time service.
-   *
-   * @var \Drupal\Component\Datetime\TimeInterface
-   */
-  protected TimeInterface $time;
-
-  /**
-   * Constructs a PrivateMessageService object.
-   *
-   * @param \Drupal\private_message\Mapper\PrivateMessageMapperInterface $mapper
-   *   The private message mapper service.
-   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
-   *   The current user.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
-   *   The configuration factory.
-   * @param \Drupal\user\UserDataInterface $userData
-   *   The user data service.
-   * @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $cacheTagsInvalidator
-   *   The cache tags invalidator interface.
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
-   *   The entity type manager interface.
-   * @param \Drupal\Component\Datetime\TimeInterface $time
-   *   The time service.
-   */
   public function __construct(
-    PrivateMessageMapperInterface $mapper,
-    AccountProxyInterface $currentUser,
-    ConfigFactoryInterface $configFactory,
-    UserDataInterface $userData,
-    CacheTagsInvalidatorInterface $cacheTagsInvalidator,
-    EntityTypeManagerInterface $entityTypeManager,
-    TimeInterface $time,
-  ) {
-    $this->mapper = $mapper;
-    $this->currentUser = $currentUser;
-    $this->configFactory = $configFactory;
-    $this->userData = $userData;
-    $this->cacheTagsInvalidator = $cacheTagsInvalidator;
-    $this->entityTypeManager = $entityTypeManager;
-    $this->time = $time;
-  }
+    protected readonly PrivateMessageMapperInterface $mapper,
+    protected readonly AccountProxyInterface $currentUser,
+    protected readonly ConfigFactoryInterface $configFactory,
+    protected readonly UserDataInterface $userData,
+    protected readonly CacheTagsInvalidatorInterface $cacheTagsInvalidator,
+    protected readonly EntityTypeManagerInterface $entityTypeManager,
+    protected readonly TimeInterface $time,
+  ) {}
 
   /**
    * {@inheritdoc}
diff --git a/src/Service/PrivateMessageThreadManager.php b/src/Service/PrivateMessageThreadManager.php
index 5ae691cc..db29e7cd 100644
--- a/src/Service/PrivateMessageThreadManager.php
+++ b/src/Service/PrivateMessageThreadManager.php
@@ -7,50 +7,27 @@ use Drupal\private_message\Entity\PrivateMessageThreadInterface;
 
 /**
  * The Private Message generator class.
- *
- * @package Drupal\private_message\Service
  */
 class PrivateMessageThreadManager implements PrivateMessageThreadManagerInterface {
 
-  /**
-   * The private message service.
-   *
-   * @var \Drupal\private_message\Service\PrivateMessageServiceInterface
-   */
-  private PrivateMessageServiceInterface $privateMessageService;
-
   /**
    * The private message.
-   *
-   * @var \Drupal\private_message\Entity\PrivateMessageInterface|null
    */
   private ?PrivateMessageInterface $message;
 
   /**
    * The message recipients.
-   *
-   * @var \Drupal\Core\Session\AccountInterface[]
    */
   private array $recipients = [];
 
   /**
    * The private message thread.
-   *
-   * @var \Drupal\private_message\Entity\PrivateMessageThreadInterface|null
    */
   private ?PrivateMessageThreadInterface $thread;
 
-  /**
-   * PrivateMessageThreadManager constructor.
-   *
-   * @param \Drupal\private_message\Service\PrivateMessageServiceInterface $privateMessageService
-   *   The private message service.
-   */
   public function __construct(
-    PrivateMessageServiceInterface $privateMessageService,
-  ) {
-    $this->privateMessageService = $privateMessageService;
-  }
+    protected readonly PrivateMessageServiceInterface $privateMessageService,
+  ) {}
 
   /**
    * {@inheritdoc}
@@ -72,7 +49,6 @@ class PrivateMessageThreadManager implements PrivateMessageThreadManagerInterfac
     if (is_null($this->thread)) {
       $this->thread = $this->privateMessageService->getThreadForMembers($this->recipients);
     }
-
     return $this;
   }
 
@@ -86,7 +62,6 @@ class PrivateMessageThreadManager implements PrivateMessageThreadManagerInterfac
       $this->thread->addMessage($this->message);
       $this->thread->save();
     }
-
     return $this;
   }
 
diff --git a/src/Traits/PrivateMessageSettingsTrait.php b/src/Traits/PrivateMessageSettingsTrait.php
new file mode 100644
index 00000000..e74e4922
--- /dev/null
+++ b/src/Traits/PrivateMessageSettingsTrait.php
@@ -0,0 +1,33 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\private_message\Traits;
+
+use Drupal\Core\Config\ImmutableConfig;
+
+/**
+ * Private Message module settings.
+ */
+trait PrivateMessageSettingsTrait {
+
+  /**
+   * Static cache of Private Message module settings.
+   */
+  protected ImmutableConfig $privateMessageSettings;
+
+  /**
+   * Returns the private message module settings.
+   *
+   * @return \Drupal\Core\Config\ImmutableConfig
+   *   The private message module settings.
+   */
+  protected function getSettings(): ImmutableConfig {
+    assert(property_exists($this, 'configFactory'));
+    if (!isset($this->privateMessageSettings)) {
+      $this->privateMessageSettings = $this->configFactory->get('private_message.settings');
+    }
+    return $this->privateMessageSettings;
+  }
+
+}
-- 
GitLab


From 1847f061e6ca4072d3022d9b391ca503c0eb8d77 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Wed, 27 Nov 2024 13:20:26 +0200
Subject: [PATCH 03/30] Unneeded PHPStan bypass

---
 .../src/Service/PrivateMessageNotifier.php                       | 1 -
 1 file changed, 1 deletion(-)

diff --git a/modules/private_message_notify/src/Service/PrivateMessageNotifier.php b/modules/private_message_notify/src/Service/PrivateMessageNotifier.php
index 3983a394..cee52869 100644
--- a/modules/private_message_notify/src/Service/PrivateMessageNotifier.php
+++ b/modules/private_message_notify/src/Service/PrivateMessageNotifier.php
@@ -175,7 +175,6 @@ class PrivateMessageNotifier implements PrivateMessageNotifierInterface {
       ]
     );
 
-    // @phpstan-ignore-next-line
     if (empty($exclude)) {
       return $recipients;
     }
-- 
GitLab


From 9c3ae6c4922f955a81cc2ba8a3f798b5fd5a3e56 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Wed, 27 Nov 2024 13:21:40 +0200
Subject: [PATCH 04/30] Remove deprecated code

---
 private_message.routing.yml       |  1 +
 src/Form/ConfirmBanUserForm.php   | 19 +++++--------------
 src/Form/ConfirmUnbanUserForm.php | 16 +++-------------
 3 files changed, 9 insertions(+), 27 deletions(-)

diff --git a/private_message.routing.yml b/private_message.routing.yml
index 8eba0891..777d5ce8 100644
--- a/private_message.routing.yml
+++ b/private_message.routing.yml
@@ -147,6 +147,7 @@ private_message.ban_user_form:
   requirements:
     _permission: 'use private messaging system,access user profiles'
     _user_is_logged_in: 'TRUE'
+    user: \d+
   options:
     parameters:
       user:
diff --git a/src/Form/ConfirmBanUserForm.php b/src/Form/ConfirmBanUserForm.php
index 1da4c1a2..37473b99 100644
--- a/src/Form/ConfirmBanUserForm.php
+++ b/src/Form/ConfirmBanUserForm.php
@@ -13,7 +13,7 @@ use Drupal\private_message\Service\PrivateMessageBanManagerInterface;
 use Drupal\user\UserInterface;
 
 /**
- * The User Ban confirmation form.
+ * The user block confirmation form.
  */
 class ConfirmBanUserForm extends ConfirmFormBase {
 
@@ -22,7 +22,7 @@ class ConfirmBanUserForm extends ConfirmFormBase {
   /**
    * The user to block.
    */
-  protected ?UserInterface $user;
+  protected UserInterface $user;
 
   public function __construct(
     protected readonly AccountProxyInterface $currentUser,
@@ -40,18 +40,8 @@ class ConfirmBanUserForm extends ConfirmFormBase {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $form_state, $user = NULL): array {
-    if (is_scalar($user)) {
-      @trigger_error('Passing $user as ' . gettype($user) . ' is deprecated in private_message:3.0.3 and is removed from private_message:4.0.0. The $user parameter should be of type UserInterface. See https://www.drupal.org/node/3484561', E_USER_DEPRECATED);
-      $this->user = $this->entityTypeManager->getStorage('user')->load($user);
-    }
-    elseif ($user instanceof UserInterface) {
-      $this->user = $user;
-    }
-    elseif ($user === NULL) {
-      return [];
-    }
-
+  public function buildForm(array $form, FormStateInterface $form_state, ?UserInterface $user = NULL): array {
+    $this->user = $user;
     return parent::buildForm($form, $form_state);
   }
 
@@ -62,6 +52,7 @@ class ConfirmBanUserForm extends ConfirmFormBase {
     // Add a security if the user id is unknown.
     if (empty($this->user)) {
       $form_state->setError($form, $this->t('The user id is unknown.'));
+      return;
     }
 
     // Add security to prevent blocking ourselves.
diff --git a/src/Form/ConfirmUnbanUserForm.php b/src/Form/ConfirmUnbanUserForm.php
index 46389676..d5b4fed8 100644
--- a/src/Form/ConfirmUnbanUserForm.php
+++ b/src/Form/ConfirmUnbanUserForm.php
@@ -21,7 +21,7 @@ class ConfirmUnbanUserForm extends ConfirmFormBase {
   /**
    * The user to unban.
    */
-  private ?UserInterface $user;
+  private UserInterface $user;
 
   public function __construct(
     protected readonly AccountProxyInterface $currentUser,
@@ -39,18 +39,8 @@ class ConfirmUnbanUserForm extends ConfirmFormBase {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $form_state, $user = NULL): array {
-    if (is_scalar($user)) {
-      @trigger_error('Passing $user as ' . gettype($user) . ' is deprecated in private_message:3.0.3 and is removed from private_message:4.0.0. The $user parameter should be of type UserInterface. See https://www.drupal.org/node/3484561', E_USER_DEPRECATED);
-      $this->user = $this->entityTypeManager->getStorage('user')->load($user);
-    }
-    elseif ($user instanceof UserInterface) {
-      $this->user = $user;
-    }
-    elseif ($user === NULL) {
-      return [];
-    }
-
+  public function buildForm(array $form, FormStateInterface $form_state, ?UserInterface $user = NULL): array {
+    $this->user = $user;
     return parent::buildForm($form, $form_state);
   }
 
-- 
GitLab


From 2725881f87511cd275c87322456d7cfdf03a141a Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Wed, 27 Nov 2024 16:55:21 +0200
Subject: [PATCH 05/30] Constructor property promotion in Ajax Commands

Note that some constructor docblocks were kept because the
documentation they provide adds some value.
---
 .../src/Service/PrivateMessageNotifier.php    |  8 +-
 ...rivateMessageInboxInsertThreadsCommand.php | 38 +++------
 ...rivateMessageInboxTriggerUpdateCommand.php |  2 +
 src/Ajax/PrivateMessageInboxUpdateCommand.php | 26 ++----
 .../PrivateMessageInsertMessagesCommand.php   | 67 ---------------
 ...rivateMessageInsertMessagesCommandBase.php | 42 +++++++++
 ...PrivateMessageInsertNewMessagesCommand.php |  8 +-
 ...teMessageInsertPreviousMessagesCommand.php | 22 +++--
 .../PrivateMessageInsertThreadCommand.php     | 21 +----
 .../PrivateMessageLoadNewMessagesCommand.php  |  2 +
 ...teMessageUpdateUnreadItemsCountCommand.php | 21 +----
 .../PrivateMessageAccessControlHandler.php    | 23 ++---
 .../PrivateMessageBanAccessControlHandler.php |  2 +
 ...ivateMessageThreadAccessControlHandler.php |  3 +-
 .../Builder/PrivateMessageBanListBuilder.php  |  2 +
 .../PrivateMessageThreadViewBuilder.php       | 28 +-----
 .../Builder/PrivateMessageViewBuilder.php     | 26 +-----
 src/Entity/PrivateMessageThreadInterface.php  |  2 +-
 src/Form/PrivateMessageForm.php               | 16 ++--
 .../Block/PrivateMessageActionsBlock.php      | 37 +-------
 src/Plugin/Block/PrivateMessageInboxBlock.php | 75 ++--------------
 .../Block/PrivateMessageNotificationBlock.php | 63 ++------------
 .../PrivateMessageThreadMemberFormatter.php   | 67 +--------------
 .../PrivateMessageThreadMessageFormatter.php  | 85 ++-----------------
 .../PrivateMessageThreadMemberWidget.php      | 19 ++---
 .../PrivateMessageConfigFormBase.php          | 23 +----
 src/Plugin/RulesAction/SendPrivateMessage.php | 24 ++++--
 .../UniqueBanConstraintValidator.php          | 30 ++-----
 .../PrivateMessageThreadHasNewMessage.php     | 23 +----
 .../PrivateMessageThreadMessagesCount.php     | 28 ++----
 .../PrivateMessageThreadNewMessagesCount.php  | 23 +----
 .../PrivateMessageThreadCleanHistory.php      | 23 +----
 .../filter/PrivateMessageThreadIsUnread.php   | 23 +----
 ...ivateMessageConfigFormManagerInterface.php |  2 +
 src/Traits/PrivateMessageSettingsTrait.php    |  2 +-
 tests/src/Kernel/EntityDeleteTest.php         |  4 +-
 36 files changed, 192 insertions(+), 718 deletions(-)
 delete mode 100644 src/Ajax/PrivateMessageInsertMessagesCommand.php
 create mode 100644 src/Ajax/PrivateMessageInsertMessagesCommandBase.php

diff --git a/modules/private_message_notify/src/Service/PrivateMessageNotifier.php b/modules/private_message_notify/src/Service/PrivateMessageNotifier.php
index cee52869..67c19183 100644
--- a/modules/private_message_notify/src/Service/PrivateMessageNotifier.php
+++ b/modules/private_message_notify/src/Service/PrivateMessageNotifier.php
@@ -101,7 +101,7 @@ class PrivateMessageNotifier implements PrivateMessageNotifierInterface {
     $notify = FALSE;
 
     // Check if notifications have been enabled.
-    if ($this->getSettings()->get('enable_notifications')) {
+    if ($this->getPrivateMessageSettings()->get('enable_notifications')) {
 
       // Eligibility to receive notifications will be checked.
       $eligible_to_receive = FALSE;
@@ -114,7 +114,7 @@ class PrivateMessageNotifier implements PrivateMessageNotifierInterface {
       }
       // Check if the user has not made any selection, and the system default is
       // to send:
-      elseif (is_null($user_default) && $this->getSettings()->get('notify_by_default')) {
+      elseif (is_null($user_default) && $this->getPrivateMessageSettings()->get('notify_by_default')) {
         $eligible_to_receive = TRUE;
       }
 
@@ -129,7 +129,7 @@ class PrivateMessageNotifier implements PrivateMessageNotifierInterface {
         // Check if the user has not yet set a value.
         if (is_null($notify_when_using)) {
           // The user has not yet set a value, so use the system default.
-          $notify_when_using = $this->getSettings()->get('notify_when_using');
+          $notify_when_using = $this->getPrivateMessageSettings()->get('notify_when_using');
         }
 
         // Get the number of seconds a user has set in their profile, after
@@ -138,7 +138,7 @@ class PrivateMessageNotifier implements PrivateMessageNotifierInterface {
         // Check if the user has not yet set a value.
         if (is_null($away_time)) {
           // The user has not yet set a value, so use the system default.
-          $away_time = $this->getSettings()->get('number_of_seconds_considered_away');
+          $away_time = $this->getPrivateMessageSettings()->get('number_of_seconds_considered_away');
         }
 
         // Check if users should always be notified.
diff --git a/src/Ajax/PrivateMessageInboxInsertThreadsCommand.php b/src/Ajax/PrivateMessageInboxInsertThreadsCommand.php
index bdc11efc..669ced29 100644
--- a/src/Ajax/PrivateMessageInboxInsertThreadsCommand.php
+++ b/src/Ajax/PrivateMessageInboxInsertThreadsCommand.php
@@ -1,39 +1,21 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Ajax;
 
+use Drupal\Component\Render\MarkupInterface;
 use Drupal\Core\Ajax\CommandInterface;
 
 /**
- * Ajax Command to insert private message inbox threads.
+ * Ajax command to insert private message inbox threads.
  */
 class PrivateMessageInboxInsertThreadsCommand implements CommandInterface {
 
-  /**
-   * The HTML for the threads to be inserted in the page.
-   *
-   * @var string
-   */
-  protected $threads;
-
-  /**
-   * Boolean to determine if there are more threads to come.
-   *
-   * @var bool
-   */
-  protected $hasNext;
-
-  /**
-   * Constructs a PrivateMessageInboxInsertThreadsCommand object.
-   *
-   * @param string $threads
-   *   The HTML for the threads to be inserted in the page.
-   * @param bool $has_next
-   *   A boolean to know if there are more threads after.
-   */
-  public function __construct($threads, $has_next) {
-    $this->threads = $threads;
-    $this->hasNext = $has_next;
+  public function __construct(
+    protected readonly MarkupInterface|string $threads,
+    protected readonly bool $hasMoreThreads,
+  ) {
   }
 
   /**
@@ -42,8 +24,8 @@ class PrivateMessageInboxInsertThreadsCommand implements CommandInterface {
   public function render() {
     return [
       'command' => 'insertInboxOldPrivateMessageThreads',
-      'threads' => $this->threads,
-      'hasNext' => $this->hasNext,
+      'threads' => (string) $this->threads,
+      'hasNext' => $this->hasMoreThreads,
     ];
   }
 
diff --git a/src/Ajax/PrivateMessageInboxTriggerUpdateCommand.php b/src/Ajax/PrivateMessageInboxTriggerUpdateCommand.php
index 0e89b4c6..572b9a0b 100644
--- a/src/Ajax/PrivateMessageInboxTriggerUpdateCommand.php
+++ b/src/Ajax/PrivateMessageInboxTriggerUpdateCommand.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Ajax;
 
 use Drupal\Core\Ajax\CommandInterface;
diff --git a/src/Ajax/PrivateMessageInboxUpdateCommand.php b/src/Ajax/PrivateMessageInboxUpdateCommand.php
index e155e242..b2910f15 100644
--- a/src/Ajax/PrivateMessageInboxUpdateCommand.php
+++ b/src/Ajax/PrivateMessageInboxUpdateCommand.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Ajax;
 
 use Drupal\Core\Ajax\CommandInterface;
@@ -10,21 +12,7 @@ use Drupal\Core\Ajax\CommandInterface;
 class PrivateMessageInboxUpdateCommand implements CommandInterface {
 
   /**
-   * The thread IDs, in the order that they should appear upon update.
-   *
-   * @var array
-   */
-  protected $threadIds;
-
-  /**
-   * HTML for any threads that don't currently exist in the inbox.
-   *
-   * @var array
-   */
-  protected $newThreads;
-
-  /**
-   * Constructs a PrivateMessageInboxUpdateCommand object.
+   * Constructs a new command instance.
    *
    * @param array $threadIds
    *   The thread IDs, in the order that they should appear when the inbox is
@@ -32,10 +20,10 @@ class PrivateMessageInboxUpdateCommand implements CommandInterface {
    * @param array $newThreads
    *   The HTML for the messages to be inserted in the page.
    */
-  public function __construct(array $threadIds, array $newThreads) {
-    $this->threadIds = $threadIds;
-    $this->newThreads = $newThreads;
-  }
+  public function __construct(
+    protected readonly array $threadIds,
+    protected readonly array $newThreads,
+  ) {}
 
   /**
    * {@inheritdoc}
diff --git a/src/Ajax/PrivateMessageInsertMessagesCommand.php b/src/Ajax/PrivateMessageInsertMessagesCommand.php
deleted file mode 100644
index f80155f2..00000000
--- a/src/Ajax/PrivateMessageInsertMessagesCommand.php
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php
-
-namespace Drupal\private_message\Ajax;
-
-use Drupal\Core\Ajax\CommandInterface;
-
-/**
- * Base class for Ajax command to insert messages into a private message thread.
- */
-abstract class PrivateMessageInsertMessagesCommand implements CommandInterface {
-
-  /**
-   * The type of messages to be inserted in the page.
-   *
-   * Possible values:
-   *   - new
-   *   - previous.
-   *
-   * @var string
-   */
-  protected $insertType;
-
-  /**
-   * The HTML for the messages to be inserted in the page.
-   *
-   * @var string
-   */
-  protected $messages;
-
-  /**
-   * The number of messages.
-   *
-   * @var int
-   */
-  protected $messagesCount;
-
-  /**
-   * Construct a PrivateMessageInsertMessagesCommand object.
-   *
-   * @param string $insertType
-   *   The type of messages to be inserted in the page. Possible values:
-   *     - new
-   *     - previous.
-   * @param string $messages
-   *   The HTML for the messages to be inserted in the page.
-   * @param int $messagesCount
-   *   The number of messages.
-   */
-  public function __construct($insertType, $messages, $messagesCount) {
-    $this->insertType = $insertType;
-    $this->messages = $messages;
-    $this->messagesCount = $messagesCount;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function render() {
-    return [
-      'command' => 'insertPrivateMessages',
-      'insertType' => $this->insertType,
-      'messages' => $this->messages,
-      'messagesCount' => $this->messagesCount,
-    ];
-  }
-
-}
diff --git a/src/Ajax/PrivateMessageInsertMessagesCommandBase.php b/src/Ajax/PrivateMessageInsertMessagesCommandBase.php
new file mode 100644
index 00000000..7007f226
--- /dev/null
+++ b/src/Ajax/PrivateMessageInsertMessagesCommandBase.php
@@ -0,0 +1,42 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\private_message\Ajax;
+
+use Drupal\Core\Ajax\CommandInterface;
+
+/**
+ * Base class for Ajax command to insert messages into a private message thread.
+ */
+abstract class PrivateMessageInsertMessagesCommandBase implements CommandInterface {
+
+  /**
+   * Constructs a new command instance.
+   *
+   * @param string $insertType
+   *   The type of messages to be inserted in the page: 'new', 'previous'.
+   * @param string $messages
+   *   The HTML for the messages to be inserted in the page.
+   * @param int $messagesCount
+   *   The number of messages.
+   */
+  public function __construct(
+    protected readonly string $insertType,
+    protected readonly string $messages,
+    protected readonly int $messagesCount,
+  ) {}
+
+  /**
+   * {@inheritdoc}
+   */
+  public function render() {
+    return [
+      'command' => 'insertPrivateMessages',
+      'insertType' => $this->insertType,
+      'messages' => $this->messages,
+      'messagesCount' => $this->messagesCount,
+    ];
+  }
+
+}
diff --git a/src/Ajax/PrivateMessageInsertNewMessagesCommand.php b/src/Ajax/PrivateMessageInsertNewMessagesCommand.php
index 0c4f6e31..856851b1 100644
--- a/src/Ajax/PrivateMessageInsertNewMessagesCommand.php
+++ b/src/Ajax/PrivateMessageInsertNewMessagesCommand.php
@@ -1,21 +1,23 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Ajax;
 
 /**
  * Class to insert new private messages into a private message thread.
  */
-class PrivateMessageInsertNewMessagesCommand extends PrivateMessageInsertMessagesCommand {
+class PrivateMessageInsertNewMessagesCommand extends PrivateMessageInsertMessagesCommandBase {
 
   /**
-   * Constructs a PrivateMessageInsertNewMessagesCommand object.
+   * Constructs a new command instance.
    *
    * @param string $messages
    *   The HTML for the messages to be inserted in the page.
    * @param int $messagesCount
    *   The number of messages.
    */
-  public function __construct($messages, $messagesCount) {
+  public function __construct(string $messages, int $messagesCount) {
     parent::__construct('new', $messages, $messagesCount);
   }
 
diff --git a/src/Ajax/PrivateMessageInsertPreviousMessagesCommand.php b/src/Ajax/PrivateMessageInsertPreviousMessagesCommand.php
index 9cf3edb5..9bf102e4 100644
--- a/src/Ajax/PrivateMessageInsertPreviousMessagesCommand.php
+++ b/src/Ajax/PrivateMessageInsertPreviousMessagesCommand.php
@@ -1,32 +1,30 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Ajax;
 
 /**
  * Class to insert older private messages into a private message thread.
  */
-class PrivateMessageInsertPreviousMessagesCommand extends PrivateMessageInsertMessagesCommand {
-
-  /**
-   * Boolean to determine if there are more threads to come.
-   *
-   * @var bool
-   */
-  protected $hasNext;
+class PrivateMessageInsertPreviousMessagesCommand extends PrivateMessageInsertMessagesCommandBase {
 
   /**
-   * Constructs a PrivateMessageInsertPreviousMessagesCommand object.
+   * Constructs a new command instance.
    *
    * @param string $messages
    *   The HTML for the messages to be inserted in the page.
    * @param int $messagesCount
    *   The number of messages.
-   * @param bool $has_next
+   * @param bool $hasNext
    *   A boolean to know if there are more messages after.
    */
-  public function __construct($messages, $messagesCount, $has_next) {
+  public function __construct(
+    string $messages,
+    int $messagesCount,
+    protected readonly bool $hasNext,
+  ) {
     parent::__construct('previous', $messages, $messagesCount);
-    $this->hasNext = $has_next;
   }
 
   /**
diff --git a/src/Ajax/PrivateMessageInsertThreadCommand.php b/src/Ajax/PrivateMessageInsertThreadCommand.php
index 687cba83..122ac58a 100644
--- a/src/Ajax/PrivateMessageInsertThreadCommand.php
+++ b/src/Ajax/PrivateMessageInsertThreadCommand.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Ajax;
 
 use Drupal\Core\Ajax\CommandInterface;
@@ -9,22 +11,7 @@ use Drupal\Core\Ajax\CommandInterface;
  */
 class PrivateMessageInsertThreadCommand implements CommandInterface {
 
-  /**
-   * The HTML of the thread to be inserted.
-   *
-   * @var string
-   */
-  protected $thread;
-
-  /**
-   * Constructs a PrivateMessageInsertThreadCommand object.
-   *
-   * @param string $thread
-   *   The HTML of the thread to be inserted.
-   */
-  public function __construct($thread) {
-    $this->thread = $thread;
-  }
+  public function __construct(protected readonly string $threadHtml) {}
 
   /**
    * {@inheritdoc}
@@ -32,7 +19,7 @@ class PrivateMessageInsertThreadCommand implements CommandInterface {
   public function render() {
     return [
       'command' => 'privateMessageInsertThread',
-      'thread' => $this->thread,
+      'thread' => $this->threadHtml,
     ];
   }
 
diff --git a/src/Ajax/PrivateMessageLoadNewMessagesCommand.php b/src/Ajax/PrivateMessageLoadNewMessagesCommand.php
index d19011e3..b7771fa9 100644
--- a/src/Ajax/PrivateMessageLoadNewMessagesCommand.php
+++ b/src/Ajax/PrivateMessageLoadNewMessagesCommand.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Ajax;
 
 use Drupal\Core\Ajax\CommandInterface;
diff --git a/src/Ajax/PrivateMessageUpdateUnreadItemsCountCommand.php b/src/Ajax/PrivateMessageUpdateUnreadItemsCountCommand.php
index c1c5dc9b..cc2af1cb 100644
--- a/src/Ajax/PrivateMessageUpdateUnreadItemsCountCommand.php
+++ b/src/Ajax/PrivateMessageUpdateUnreadItemsCountCommand.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Ajax;
 
 use Drupal\Core\Ajax\CommandInterface;
@@ -12,22 +14,7 @@ use Drupal\Core\Ajax\CommandInterface;
  */
 class PrivateMessageUpdateUnreadItemsCountCommand implements CommandInterface {
 
-  /**
-   * The number of unread threads.
-   *
-   * @var int
-   */
-  protected $unreadItemsCount;
-
-  /**
-   * Constructs a PrivateMessageUpdateUnreadItemsCountCommand object.
-   *
-   * @param int $unreadItemsCount
-   *   The number of unread threads.
-   */
-  public function __construct($unreadItemsCount) {
-    $this->unreadItemsCount = $unreadItemsCount;
-  }
+  public function __construct(protected readonly int $unreadThreadsCount) {}
 
   /**
    * {@inheritdoc}
@@ -35,7 +22,7 @@ class PrivateMessageUpdateUnreadItemsCountCommand implements CommandInterface {
   public function render() {
     return [
       'command' => 'privateMessageUpdateUnreadItemsCount',
-      'unreadItemsCount' => $this->unreadItemsCount,
+      'unreadItemsCount' => $this->unreadThreadsCount,
     ];
   }
 
diff --git a/src/Entity/Access/PrivateMessageAccessControlHandler.php b/src/Entity/Access/PrivateMessageAccessControlHandler.php
index fb1845f2..7fe34d69 100644
--- a/src/Entity/Access/PrivateMessageAccessControlHandler.php
+++ b/src/Entity/Access/PrivateMessageAccessControlHandler.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Entity\Access;
 
 use Drupal\Core\Access\AccessResult;
@@ -16,24 +18,11 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 class PrivateMessageAccessControlHandler extends EntityAccessControlHandler implements EntityHandlerInterface {
 
-  /**
-   * The private message service.
-   *
-   * @var \Drupal\private_message\Service\PrivateMessageServiceInterface
-   */
-  protected $privateMessageService;
-
-  /**
-   * Constructs a PrivateMessageThreadAccessControlHandler entity.
-   *
-   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
-   *   The entity type.
-   * @param \Drupal\private_message\Service\PrivateMessageServiceInterface $privateMessageService
-   *   The private message service.
-   */
-  public function __construct(EntityTypeInterface $entity_type, PrivateMessageServiceInterface $privateMessageService) {
+  public function __construct(
+    EntityTypeInterface $entity_type,
+    protected readonly PrivateMessageServiceInterface $privateMessageService,
+  ) {
     parent::__construct($entity_type);
-    $this->privateMessageService = $privateMessageService;
   }
 
   /**
diff --git a/src/Entity/Access/PrivateMessageBanAccessControlHandler.php b/src/Entity/Access/PrivateMessageBanAccessControlHandler.php
index a4171f8c..07d8b9c3 100644
--- a/src/Entity/Access/PrivateMessageBanAccessControlHandler.php
+++ b/src/Entity/Access/PrivateMessageBanAccessControlHandler.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Entity\Access;
 
 use Drupal\Core\Access\AccessResult;
diff --git a/src/Entity/Access/PrivateMessageThreadAccessControlHandler.php b/src/Entity/Access/PrivateMessageThreadAccessControlHandler.php
index 47d0716e..85cc6b88 100644
--- a/src/Entity/Access/PrivateMessageThreadAccessControlHandler.php
+++ b/src/Entity/Access/PrivateMessageThreadAccessControlHandler.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Entity\Access;
 
 use Drupal\Core\Access\AccessResult;
@@ -16,7 +18,6 @@ class PrivateMessageThreadAccessControlHandler extends EntityAccessControlHandle
    * {@inheritdoc}
    */
   protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
-
     if ($account->hasPermission('administer private messages')) {
       return AccessResult::allowed();
     }
diff --git a/src/Entity/Builder/PrivateMessageBanListBuilder.php b/src/Entity/Builder/PrivateMessageBanListBuilder.php
index 8f727a3e..0d195bfe 100644
--- a/src/Entity/Builder/PrivateMessageBanListBuilder.php
+++ b/src/Entity/Builder/PrivateMessageBanListBuilder.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Entity\Builder;
 
 use Drupal\Core\Entity\EntityInterface;
diff --git a/src/Entity/Builder/PrivateMessageThreadViewBuilder.php b/src/Entity/Builder/PrivateMessageThreadViewBuilder.php
index 563f7b51..7e54df9e 100644
--- a/src/Entity/Builder/PrivateMessageThreadViewBuilder.php
+++ b/src/Entity/Builder/PrivateMessageThreadViewBuilder.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Entity\Builder;
 
 use Drupal\Core\Cache\Cache;
@@ -19,39 +21,15 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 class PrivateMessageThreadViewBuilder extends EntityViewBuilder {
 
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected AccountProxyInterface $currentUser;
-
-  /**
-   * Constructs a PrivateMessageThreadViewBuilder object.
-   *
-   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
-   *   The entity type.
-   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
-   *   The entity repository service.
-   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
-   *   The language manager service.
-   * @param \Drupal\Core\Theme\Registry $theme_registry
-   *   The theme register.
-   * @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository
-   *   The entity display repository.
-   * @param \Drupal\Core\Session\AccountProxyInterface $current_user
-   *   The current user.
-   */
   public function __construct(
     EntityTypeInterface $entity_type,
     EntityRepositoryInterface $entity_repository,
     LanguageManagerInterface $language_manager,
     Registry $theme_registry,
     EntityDisplayRepositoryInterface $entity_display_repository,
-    AccountProxyInterface $current_user,
+    protected readonly AccountProxyInterface $currentUser,
   ) {
     parent::__construct($entity_type, $entity_repository, $language_manager, $theme_registry, $entity_display_repository);
-    $this->currentUser = $current_user;
   }
 
   /**
diff --git a/src/Entity/Builder/PrivateMessageViewBuilder.php b/src/Entity/Builder/PrivateMessageViewBuilder.php
index 3ccf3c04..a6d46f87 100644
--- a/src/Entity/Builder/PrivateMessageViewBuilder.php
+++ b/src/Entity/Builder/PrivateMessageViewBuilder.php
@@ -17,39 +17,15 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 class PrivateMessageViewBuilder extends EntityViewBuilder {
 
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected AccountProxyInterface $currentUser;
-
-  /**
-   * Constructs a PrivateMessageViewBuilder object.
-   *
-   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
-   *   The entity type definition.
-   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
-   *   The entity repository service.
-   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
-   *   The language manager.
-   * @param \Drupal\Core\Theme\Registry $theme_registry
-   *   The theme registry.
-   * @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository
-   *   The entity display repository.
-   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
-   *   The current user.
-   */
   public function __construct(
     EntityTypeInterface $entity_type,
     EntityRepositoryInterface $entity_repository,
     LanguageManagerInterface $language_manager,
     Registry $theme_registry,
     EntityDisplayRepositoryInterface $entity_display_repository,
-    AccountProxyInterface $currentUser,
+    protected readonly AccountProxyInterface $currentUser,
   ) {
     parent::__construct($entity_type, $entity_repository, $language_manager, $theme_registry, $entity_display_repository);
-    $this->currentUser = $currentUser;
   }
 
   /**
diff --git a/src/Entity/PrivateMessageThreadInterface.php b/src/Entity/PrivateMessageThreadInterface.php
index cab0cebb..f58ae2e5 100644
--- a/src/Entity/PrivateMessageThreadInterface.php
+++ b/src/Entity/PrivateMessageThreadInterface.php
@@ -15,7 +15,7 @@ interface PrivateMessageThreadInterface extends ContentEntityInterface {
   /**
    * Add a member to the private message thread.
    *
-   * @param \Drupal\user\AccountInterface $account
+   * @param \Drupal\Core\Session\AccountInterface $account
    *   The account to be set as a member of the private message thread.
    *
    * @return \Drupal\private_message\Entity\PrivateMessageInterface
diff --git a/src/Form/PrivateMessageForm.php b/src/Form/PrivateMessageForm.php
index a0307414..26588c08 100644
--- a/src/Form/PrivateMessageForm.php
+++ b/src/Form/PrivateMessageForm.php
@@ -100,9 +100,9 @@ class PrivateMessageForm extends ContentEntityForm {
       foreach ($bannedUsers as $bannedUser) {
         if (\in_array($bannedUser, $threadMembers)) {
 
-          if (!empty($this->getSettings()->get('ban_message'))) {
+          if (!empty($this->getPrivateMessageSettings()->get('ban_message'))) {
             $this->messenger()
-              ->addError($this->getSettings()->get('ban_message'));
+              ->addError($this->getPrivateMessageSettings()->get('ban_message'));
 
             $form['message_for_user'] = [
               StatusMessages::renderMessages(),
@@ -118,16 +118,16 @@ class PrivateMessageForm extends ContentEntityForm {
 
       // Block messaging form for active blocking mode.
       if (!$banned) {
-        $ban_mode = $this->getSettings()->get('ban_mode');
+        $ban_mode = $this->getPrivateMessageSettings()->get('ban_mode');
         if ($ban_mode === BlockType::Active) {
 
           foreach ($threadMembers as $threadMember) {
             $bannedUsers = $this->privateMessageBanManager->getBannedUsers($threadMember);
             if (in_array($this->currentUser()->id(), $bannedUsers)) {
 
-              if (!empty($this->getSettings()->get('ban_message'))) {
+              if (!empty($this->getPrivateMessageSettings()->get('ban_message'))) {
                 $this->messenger()
-                  ->addError($this->getSettings()->get('ban_message'));
+                  ->addError($this->getPrivateMessageSettings()->get('ban_message'));
 
                 $form['message_for_user'] = [
                   StatusMessages::renderMessages(),
@@ -151,8 +151,8 @@ class PrivateMessageForm extends ContentEntityForm {
 
         // Only to do these when using #ajax.
         $form['#attached']['library'][] = 'private_message/message_form';
-        $form['#attached']['drupalSettings']['privateMessageSendKey'] = $this->getSettings()->get('keys_send');
-        $autofocus_enabled = $this->getSettings()->get('autofocus_enable');
+        $form['#attached']['drupalSettings']['privateMessageSendKey'] = $this->getPrivateMessageSettings()->get('keys_send');
+        $autofocus_enabled = $this->getPrivateMessageSettings()->get('autofocus_enable');
         if ($autofocus_enabled) {
           $form['message']['widget'][0]['#attributes']['autofocus'] = 'autofocus';
         }
@@ -190,7 +190,7 @@ class PrivateMessageForm extends ContentEntityForm {
 
     $form['#validate'][] = '::validateBannedMembers';
 
-    if ($save_label = $this->getSettings()->get('save_message_label')) {
+    if ($save_label = $this->getPrivateMessageSettings()->get('save_message_label')) {
       $form['actions']['submit']['#value'] = $save_label;
     }
 
diff --git a/src/Plugin/Block/PrivateMessageActionsBlock.php b/src/Plugin/Block/PrivateMessageActionsBlock.php
index fb2b0538..6d2906e5 100644
--- a/src/Plugin/Block/PrivateMessageActionsBlock.php
+++ b/src/Plugin/Block/PrivateMessageActionsBlock.php
@@ -5,7 +5,7 @@ namespace Drupal\private_message\Plugin\Block;
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Block\BlockBase;
-use Drupal\Core\Config\ConfigFactory;
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\AccountProxyInterface;
@@ -25,45 +25,14 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 class PrivateMessageActionsBlock extends BlockBase implements ContainerFactoryPluginInterface {
 
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected AccountProxyInterface $currentUser;
-
-  /**
-   * Configuration Factory.
-   *
-   * @var \Drupal\Core\Config\ConfigFactory
-   */
-  protected ConfigFactory $configFactory;
-
-  /**
-   * Constructs a PrivateMessageForm object.
-   *
-   * @param array $configuration
-   *   The block configuration.
-   * @param string $plugin_id
-   *   The ID of the plugin.
-   * @param mixed $plugin_definition
-   *   The plugin definition.
-   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
-   *   The current user.
-   * @param \Drupal\Core\Config\ConfigFactory $configFactory
-   *   The config factory service.
-   */
   public function __construct(
     array $configuration,
     $plugin_id,
     $plugin_definition,
-    AccountProxyInterface $currentUser,
-    ConfigFactory $configFactory,
+    protected readonly AccountProxyInterface $currentUser,
+    protected readonly ConfigFactoryInterface $configFactory,
   ) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
-
-    $this->currentUser = $currentUser;
-    $this->configFactory = $configFactory;
   }
 
   /**
diff --git a/src/Plugin/Block/PrivateMessageInboxBlock.php b/src/Plugin/Block/PrivateMessageInboxBlock.php
index c5b582b1..59746b67 100644
--- a/src/Plugin/Block/PrivateMessageInboxBlock.php
+++ b/src/Plugin/Block/PrivateMessageInboxBlock.php
@@ -8,7 +8,6 @@ use Drupal\Core\Access\CsrfTokenGenerator;
 use Drupal\Core\Block\BlockBase;
 use Drupal\Core\Block\BlockPluginInterface;
 use Drupal\Core\Cache\Cache;
-use Drupal\Core\Config\Config;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Form\FormStateInterface;
@@ -17,6 +16,7 @@ use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\Core\Url;
 use Drupal\private_message\Service\PrivateMessageServiceInterface;
+use Drupal\private_message\Traits\PrivateMessageSettingsTrait;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -30,78 +30,19 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 class PrivateMessageInboxBlock extends BlockBase implements BlockPluginInterface, ContainerFactoryPluginInterface {
 
-  /**
-   * The private message service.
-   *
-   * @var \Drupal\private_message\Service\PrivateMessageServiceInterface
-   */
-  protected PrivateMessageServiceInterface $privateMessageService;
-
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected AccountProxyInterface $currentUser;
+  use PrivateMessageSettingsTrait;
 
-  /**
-   * The entity manager service.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected EntityTypeManagerInterface $entityTypeManager;
-
-  /**
-   * The CSRF token generator service.
-   *
-   * @var \Drupal\Core\Access\CsrfTokenGenerator
-   */
-  protected CsrfTokenGenerator $csrfToken;
-
-  /**
-   * The private message configuration.
-   *
-   * @var \Drupal\Core\Config\Config
-   */
-  protected Config $privateMessageConfig;
-
-  /**
-   * Constructs a PrivateMessageForm object.
-   *
-   * @param array $configuration
-   *   The block configuration.
-   * @param string $plugin_id
-   *   The ID of the plugin.
-   * @param mixed $plugin_definition
-   *   The plugin definition.
-   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
-   *   The current user.
-   * @param \Drupal\private_message\Service\PrivateMessageServiceInterface $privateMessageService
-   *   The private message service.
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
-   *   The entity manager service.
-   * @param \Drupal\Core\Access\CsrfTokenGenerator $csrfToken
-   *   The CSRF token generator service.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $config
-   *   The config service.
-   */
   public function __construct(
     array $configuration,
     $plugin_id,
     $plugin_definition,
-    AccountProxyInterface $currentUser,
-    PrivateMessageServiceInterface $privateMessageService,
-    EntityTypeManagerInterface $entityTypeManager,
-    CsrfTokenGenerator $csrfToken,
-    ConfigFactoryInterface $config,
+    protected readonly AccountProxyInterface $currentUser,
+    protected readonly PrivateMessageServiceInterface $privateMessageService,
+    protected readonly EntityTypeManagerInterface $entityTypeManager,
+    protected readonly CsrfTokenGenerator $csrfToken,
+    protected readonly ConfigFactoryInterface $configFactory,
   ) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
-
-    $this->currentUser = $currentUser;
-    $this->privateMessageService = $privateMessageService;
-    $this->entityTypeManager = $entityTypeManager;
-    $this->csrfToken = $csrfToken;
-    $this->privateMessageConfig = $config->get('private_message.settings');
   }
 
   /**
@@ -146,7 +87,7 @@ class PrivateMessageInboxBlock extends BlockBase implements BlockPluginInterface
       }
 
       $block['#attached']['library'][] = 'private_message/inbox_block_script';
-      $style_disabled = $this->privateMessageConfig->get('remove_css');
+      $style_disabled = $this->getPrivateMessageSettings()->get('remove_css');
       if (!$style_disabled) {
         $block['#attached']['library'][] = 'private_message/inbox_block_style';
       }
diff --git a/src/Plugin/Block/PrivateMessageNotificationBlock.php b/src/Plugin/Block/PrivateMessageNotificationBlock.php
index 5286dac9..daa72055 100644
--- a/src/Plugin/Block/PrivateMessageNotificationBlock.php
+++ b/src/Plugin/Block/PrivateMessageNotificationBlock.php
@@ -8,7 +8,6 @@ use Drupal\Core\Access\CsrfTokenGenerator;
 use Drupal\Core\Block\BlockBase;
 use Drupal\Core\Block\BlockPluginInterface;
 use Drupal\Core\Cache\Cache;
-use Drupal\Core\Config\Config;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
@@ -16,6 +15,7 @@ use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\Core\Url;
 use Drupal\private_message\Service\PrivateMessageServiceInterface;
+use Drupal\private_message\Traits\PrivateMessageSettingsTrait;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -29,67 +29,18 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 class PrivateMessageNotificationBlock extends BlockBase implements BlockPluginInterface, ContainerFactoryPluginInterface {
 
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected AccountProxyInterface $currentUser;
-
-  /**
-   * The CSRF token generator service.
-   *
-   * @var \Drupal\Core\Access\CsrfTokenGenerator
-   */
-  protected CsrfTokenGenerator $csrfToken;
-
-  /**
-   * The private message service.
-   *
-   * @var \Drupal\private_message\Service\PrivateMessageServiceInterface
-   */
-  protected PrivateMessageServiceInterface $privateMessageService;
-
-  /**
-   * The private message configuration.
-   *
-   * @var \Drupal\Core\Config\Config
-   */
-  protected Config $privateMessageConfig;
+  use PrivateMessageSettingsTrait;
 
-  /**
-   * Constructs a PrivateMessageForm object.
-   *
-   * @param array $configuration
-   *   The block configuration.
-   * @param string $plugin_id
-   *   The ID of the plugin.
-   * @param mixed $plugin_definition
-   *   The plugin definition.
-   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
-   *   The current user.
-   * @param \Drupal\Core\Access\CsrfTokenGenerator $csrfToken
-   *   The CSRF token generator service.
-   * @param \Drupal\private_message\Service\PrivateMessageServiceInterface $privateMessageService
-   *   The private message service.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $config
-   *   The config service.
-   */
   public function __construct(
     array $configuration,
     $plugin_id,
     $plugin_definition,
-    AccountProxyInterface $currentUser,
-    CsrfTokenGenerator $csrfToken,
-    PrivateMessageServiceInterface $privateMessageService,
-    ConfigFactoryInterface $config,
+    protected readonly AccountProxyInterface $currentUser,
+    protected readonly CsrfTokenGenerator $csrfToken,
+    protected readonly PrivateMessageServiceInterface $privateMessageService,
+    protected readonly ConfigFactoryInterface $configFactory,
   ) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
-
-    $this->currentUser = $currentUser;
-    $this->csrfToken = $csrfToken;
-    $this->privateMessageService = $privateMessageService;
-    $this->privateMessageConfig = $config->get('private_message.settings');
   }
 
   /**
@@ -148,7 +99,7 @@ class PrivateMessageNotificationBlock extends BlockBase implements BlockPluginIn
     $block['#attached']['drupalSettings']['privateMessageNotificationBlock']['ajaxRefreshRate'] = $config['ajax_refresh_rate'];
 
     $block['#attached']['library'][] = 'private_message/notification_block_script';
-    $style_disabled = $this->privateMessageConfig->get('remove_css');
+    $style_disabled = $this->getPrivateMessageSettings()->get('remove_css');
     if (!$style_disabled) {
       $block['#attached']['library'][] = 'private_message/notification_block_style';
     }
diff --git a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMemberFormatter.php b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMemberFormatter.php
index c30079bb..b1dc5d96 100644
--- a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMemberFormatter.php
+++ b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMemberFormatter.php
@@ -28,60 +28,6 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 class PrivateMessageThreadMemberFormatter extends FormatterBase implements ContainerFactoryPluginInterface {
 
-  /**
-   * The entity manager service.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected EntityTypeManagerInterface $entityTypeManager;
-
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected AccountProxyInterface $currentUser;
-
-  /**
-   * The entity display repository.
-   *
-   * @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface
-   */
-  protected EntityDisplayRepositoryInterface $entityDisplayRepository;
-
-  /**
-   * The renderer service.
-   *
-   * @var \Drupal\Core\Render\RendererInterface
-   */
-  protected RendererInterface $renderer;
-
-  /**
-   * Construct a PrivateMessageThreadFormatter object.
-   *
-   * @param string $plugin_id
-   *   The ID of the plugin.
-   * @param mixed $plugin_definition
-   *   The plugin definition.
-   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
-   *   The field definition.
-   * @param array $settings
-   *   The field settings.
-   * @param mixed $label
-   *   The label of the field.
-   * @param string $view_mode
-   *   The current view mode.
-   * @param array $third_party_settings
-   *   The third party settings.
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
-   *   The entity manager service.
-   * @param \Drupal\Core\Session\AccountProxyInterface $current_user
-   *   The current user.
-   * @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository
-   *   The entity display repository.
-   * @param \Drupal\Core\Render\Renderer $renderer
-   *   The renderer.
-   */
   public function __construct(
     $plugin_id,
     $plugin_definition,
@@ -90,17 +36,12 @@ class PrivateMessageThreadMemberFormatter extends FormatterBase implements Conta
     $label,
     $view_mode,
     array $third_party_settings,
-    EntityTypeManagerInterface $entity_type_manager,
-    AccountProxyInterface $current_user,
-    EntityDisplayRepositoryInterface $entity_display_repository,
-    RendererInterface $renderer,
+    protected readonly EntityTypeManagerInterface $entityTypeManager,
+    protected readonly AccountProxyInterface $currentUser,
+    protected readonly EntityDisplayRepositoryInterface $entityDisplayRepository,
+    protected readonly RendererInterface $renderer,
   ) {
     parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
-
-    $this->entityTypeManager = $entity_type_manager;
-    $this->currentUser = $current_user;
-    $this->entityDisplayRepository = $entity_display_repository;
-    $this->renderer = $renderer;
   }
 
   /**
diff --git a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php
index a80ff7fe..ad42381d 100644
--- a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php
+++ b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php
@@ -3,7 +3,6 @@
 namespace Drupal\private_message\Plugin\Field\FieldFormatter;
 
 use Drupal\Core\Access\CsrfTokenGenerator;
-use Drupal\Core\Config\Config;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
@@ -14,6 +13,7 @@ use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\Core\Url;
+use Drupal\private_message\Traits\PrivateMessageSettingsTrait;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -29,69 +29,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 class PrivateMessageThreadMessageFormatter extends FormatterBase implements ContainerFactoryPluginInterface {
 
-  /**
-   * The entity manager service.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected EntityTypeManagerInterface $entityTypeManager;
-
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountProxyInterface
-   */
-  protected AccountProxyInterface $currentUser;
-
-  /**
-   * The CSRF token generator.
-   *
-   * @var \Drupal\Core\Access\CsrfTokenGenerator
-   */
-  protected CsrfTokenGenerator $csrfTokenGenerator;
+  use PrivateMessageSettingsTrait;
 
-  /**
-   * The configuration factory.
-   *
-   * @var \Drupal\Core\Config\Config
-   */
-  protected Config $config;
-
-  /**
-   * The entity display repository.
-   *
-   * @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface
-   */
-  protected EntityDisplayRepositoryInterface $entityDisplayRepository;
-
-  /**
-   * Construct a PrivateMessageThreadFormatter object.
-   *
-   * @param string $plugin_id
-   *   The ID of the plugin.
-   * @param mixed $plugin_definition
-   *   The plugin definition.
-   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
-   *   The field definition.
-   * @param array $settings
-   *   The field settings.
-   * @param mixed $label
-   *   The label of the field.
-   * @param string $view_mode
-   *   The current view mode.
-   * @param array $third_party_settings
-   *   The third party settings.
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
-   *   The entity manager service.
-   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
-   *   The current user.
-   * @param \Drupal\Core\Access\CsrfTokenGenerator $csrfTokenGenerator
-   *   The CSRF token generator.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
-   *   The configuration factory.
-   * @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository
-   *   The entity display repository.
-   */
   public function __construct(
     $plugin_id,
     $plugin_definition,
@@ -100,19 +39,13 @@ class PrivateMessageThreadMessageFormatter extends FormatterBase implements Cont
     $label,
     $view_mode,
     array $third_party_settings,
-    EntityTypeManagerInterface $entityTypeManager,
-    AccountProxyInterface $currentUser,
-    CsrfTokenGenerator $csrfTokenGenerator,
-    ConfigFactoryInterface $configFactory,
-    EntityDisplayRepositoryInterface $entity_display_repository,
+    protected readonly EntityTypeManagerInterface $entityTypeManager,
+    protected readonly AccountProxyInterface $currentUser,
+    protected readonly CsrfTokenGenerator $csrfTokenGenerator,
+    protected readonly ConfigFactoryInterface $configFactory,
+    protected readonly EntityDisplayRepositoryInterface $entityDisplayRepository,
   ) {
     parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
-
-    $this->entityTypeManager = $entityTypeManager;
-    $this->currentUser = $currentUser;
-    $this->csrfTokenGenerator = $csrfTokenGenerator;
-    $this->config = $configFactory->get('private_message.settings');
-    $this->entityDisplayRepository = $entity_display_repository;
   }
 
   /**
@@ -162,7 +95,7 @@ class PrivateMessageThreadMessageFormatter extends FormatterBase implements Cont
    */
   public function settingsSummary(): array {
     $summary = [];
-    $settings = $this->getSettings();
+    $settings = $this->getPrivateMessageSettings();
 
     $summary['message_count'] = $this->t('Number of threads to show on load: @count', ['@count' => $settings['message_count']]);
     $summary['ajax_previous_load_count'] = $this->t('Number of threads to show when clicking load previous: @count', ['@count' => $settings['ajax_previous_load_count']]);
@@ -303,7 +236,7 @@ class PrivateMessageThreadMessageFormatter extends FormatterBase implements Cont
     ];
 
     $element['#attached']['library'][] = 'private_message/private_message_thread_script';
-    $style_disabled = $this->config->get('remove_css');
+    $style_disabled = $this->getPrivateMessageSettings()->get('remove_css');
     if (!$style_disabled) {
       $element['#attached']['library'][] = 'private_message/private_message_thread_style';
     }
diff --git a/src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php b/src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php
index 6eb05932..25d8f4c9 100644
--- a/src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php
+++ b/src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php
@@ -5,7 +5,6 @@ declare(strict_types=1);
 namespace Drupal\private_message\Plugin\Field\FieldWidget;
 
 use Drupal\Component\Utility\NestedArray;
-use Drupal\Core\Config\Config;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Field\Attribute\FieldWidget;
@@ -15,6 +14,7 @@ use Drupal\Core\Field\Plugin\Field\FieldWidget\EntityReferenceAutocompleteWidget
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\private_message\Traits\PrivateMessageSettingsTrait;
 use Drupal\user\UserInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\RequestStack;
@@ -31,12 +31,7 @@ use Symfony\Component\HttpFoundation\RequestStack;
 )]
 class PrivateMessageThreadMemberWidget extends EntityReferenceAutocompleteWidget implements ContainerFactoryPluginInterface {
 
-  /**
-   * The configuration factory.
-   *
-   * @var \Drupal\Core\Config\Config
-   */
-  protected Config $config;
+  use PrivateMessageSettingsTrait;
 
   public function __construct(
     string $plugin_id,
@@ -44,13 +39,11 @@ class PrivateMessageThreadMemberWidget extends EntityReferenceAutocompleteWidget
     FieldDefinitionInterface $field_definition,
     array $settings,
     array $third_party_settings,
-    protected RequestStack $requestStack,
-    protected EntityTypeManagerInterface $entityTypeManager,
-    ConfigFactoryInterface $config_factory,
+    protected readonly RequestStack $requestStack,
+    protected readonly EntityTypeManagerInterface $entityTypeManager,
+    protected readonly ConfigFactoryInterface $configFactory,
   ) {
     parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings);
-
-    $this->config = $config_factory->get('private_message.settings');
   }
 
   /**
@@ -143,7 +136,7 @@ class PrivateMessageThreadMemberWidget extends EntityReferenceAutocompleteWidget
       $element['target_id']['#default_value'] = $recipient;
     }
 
-    if ($recipient && $this->config->get('hide_recipient_field_when_prefilled')) {
+    if ($recipient && $this->getPrivateMessageSettings()->get('hide_recipient_field_when_prefilled')) {
       $maxMembers = 1;
     }
 
diff --git a/src/Plugin/PrivateMessageConfigForm/PrivateMessageConfigFormBase.php b/src/Plugin/PrivateMessageConfigForm/PrivateMessageConfigFormBase.php
index 986c7a3b..8b527411 100644
--- a/src/Plugin/PrivateMessageConfigForm/PrivateMessageConfigFormBase.php
+++ b/src/Plugin/PrivateMessageConfigForm/PrivateMessageConfigFormBase.php
@@ -12,34 +12,13 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 abstract class PrivateMessageConfigFormBase extends PluginBase implements PrivateMessageConfigFormPluginInterface {
 
-  /**
-   * The private message config form plugin manager.
-   *
-   * @var \Drupal\Core\Config\ConfigFactoryInterface
-   */
-  protected ConfigFactoryInterface $configFactory;
-
-  /**
-   * Constructs a PrivateMessageForm object.
-   *
-   * @param array $configuration
-   *   The plugin configuration.
-   * @param string $plugin_id
-   *   The plugin ID.
-   * @param mixed $plugin_definition
-   *   The plugin definitions.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
-   *   The configuration factory service.
-   */
   public function __construct(
     array $configuration,
     $plugin_id,
     $plugin_definition,
-    ConfigFactoryInterface $configFactory,
+    protected ConfigFactoryInterface $configFactory,
   ) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
-
-    $this->configFactory = $configFactory;
   }
 
   /**
diff --git a/src/Plugin/RulesAction/SendPrivateMessage.php b/src/Plugin/RulesAction/SendPrivateMessage.php
index 5d6eb982..0fd6c7c7 100644
--- a/src/Plugin/RulesAction/SendPrivateMessage.php
+++ b/src/Plugin/RulesAction/SendPrivateMessage.php
@@ -4,6 +4,7 @@ namespace Drupal\private_message\Plugin\RulesAction;
 
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\private_message\Entity\PrivateMessage;
+use Drupal\private_message\Service\PrivateMessageServiceInterface;
 use Drupal\rules\Core\RulesActionBase;
 use Drupal\user\UserInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -33,20 +34,25 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 class SendPrivateMessage extends RulesActionBase implements ContainerFactoryPluginInterface {
 
-  /**
-   * The Private Message service.
-   *
-   * @var \Drupal\private_message\Service\PrivateMessageService
-   */
-  protected $privateMessageService;
+  public function __construct(
+    array $configuration,
+    $plugin_id,
+    $plugin_definition,
+    protected readonly PrivateMessageServiceInterface $privateMessageService,
+  ) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+  }
 
   /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
-    $instance = new static($configuration, $plugin_id, $plugin_definition);
-    $instance->privateMessageService = $container->get('private_message.service');
-    return $instance;
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('private_message.service'),
+    );
   }
 
   /**
diff --git a/src/Plugin/Validation/Constraint/UniqueBanConstraintValidator.php b/src/Plugin/Validation/Constraint/UniqueBanConstraintValidator.php
index f816342a..eeaf2d2b 100644
--- a/src/Plugin/Validation/Constraint/UniqueBanConstraintValidator.php
+++ b/src/Plugin/Validation/Constraint/UniqueBanConstraintValidator.php
@@ -2,10 +2,10 @@
 
 namespace Drupal\private_message\Plugin\Validation\Constraint;
 
+use Drupal\Core\DependencyInjection\AutowireTrait;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\private_message\Entity\PrivateMessageBan;
-use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\Validator\Constraint;
 use Symfony\Component\Validator\ConstraintValidator;
 
@@ -14,31 +14,11 @@ use Symfony\Component\Validator\ConstraintValidator;
  */
 class UniqueBanConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface {
 
-  /**
-   * The entity type manager.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected $entityTypeManager;
-
-  /**
-   * Creates a new UniqueBanConstraintValidator instance.
-   *
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
-   *   The entity type manager.
-   */
-  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
-    $this->entityTypeManager = $entity_type_manager;
-  }
+  use AutowireTrait;
 
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('entity_type.manager')
-    );
-  }
+  public function __construct(
+    protected readonly EntityTypeManagerInterface $entityTypeManager,
+  ) {}
 
   /**
    * {@inheritdoc}
diff --git a/src/Plugin/views/field/PrivateMessageThreadHasNewMessage.php b/src/Plugin/views/field/PrivateMessageThreadHasNewMessage.php
index fa50fc4a..f8527561 100644
--- a/src/Plugin/views/field/PrivateMessageThreadHasNewMessage.php
+++ b/src/Plugin/views/field/PrivateMessageThreadHasNewMessage.php
@@ -17,33 +17,14 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 class PrivateMessageThreadHasNewMessage extends FieldPluginBase {
 
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountInterface
-   */
-  protected $currentUser;
-
-  /**
-   * The private message mapper service.
-   *
-   * @var \Drupal\private_message\Mapper\PrivateMessageMapperInterface
-   */
-  protected PrivateMessageMapperInterface $mapper;
-
-  /**
-   * Creates an instance of PrivateMessageThreadHasNewMessage.
-   */
   public function __construct(
     array $configuration,
     $plugin_id,
     $plugin_definition,
-    AccountInterface $current_user,
-    PrivateMessageMapperInterface $mapper,
+    protected readonly AccountInterface $currentUser,
+    protected readonly PrivateMessageMapperInterface $mapper,
   ) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
-    $this->currentUser = $current_user;
-    $this->mapper = $mapper;
   }
 
   /**
diff --git a/src/Plugin/views/field/PrivateMessageThreadMessagesCount.php b/src/Plugin/views/field/PrivateMessageThreadMessagesCount.php
index 6cd318a5..c67accce 100644
--- a/src/Plugin/views/field/PrivateMessageThreadMessagesCount.php
+++ b/src/Plugin/views/field/PrivateMessageThreadMessagesCount.php
@@ -16,29 +16,13 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 class PrivateMessageThreadMessagesCount extends FieldPluginBase {
 
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountInterface
-   */
-  protected $currentUser;
-
-  /**
-   * Constructs a PrivateMessageThreadMessagesCount object.
-   *
-   * @param array $configuration
-   *   A configuration array containing information about the plugin instance.
-   * @param string $plugin_id
-   *   The plugin_id for the plugin instance.
-   * @param mixed $plugin_definition
-   *   The plugin implementation definition.
-   * @param \Drupal\Core\Session\AccountInterface $current_user
-   *   The current user.
-   */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, AccountInterface $current_user) {
+  public function __construct(
+    array $configuration,
+    $plugin_id,
+    $plugin_definition,
+    protected readonly AccountInterface $currentUser,
+  ) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
-
-    $this->currentUser = $current_user;
   }
 
   /**
diff --git a/src/Plugin/views/field/PrivateMessageThreadNewMessagesCount.php b/src/Plugin/views/field/PrivateMessageThreadNewMessagesCount.php
index f2ca43d8..5c5d6228 100644
--- a/src/Plugin/views/field/PrivateMessageThreadNewMessagesCount.php
+++ b/src/Plugin/views/field/PrivateMessageThreadNewMessagesCount.php
@@ -17,33 +17,14 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 class PrivateMessageThreadNewMessagesCount extends FieldPluginBase {
 
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountInterface
-   */
-  protected $currentUser;
-
-  /**
-   * The private message mapper service.
-   *
-   * @var \Drupal\private_message\Mapper\PrivateMessageMapperInterface
-   */
-  protected PrivateMessageMapperInterface $mapper;
-
-  /**
-   * Creates an instance of PrivateMessageThreadNewMessagesCount.
-   */
   public function __construct(
     array $configuration,
     $plugin_id,
     $plugin_definition,
-    AccountInterface $current_user,
-    PrivateMessageMapperInterface $mapper,
+    protected readonly AccountInterface $currentUser,
+    protected readonly PrivateMessageMapperInterface $mapper,
   ) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
-    $this->currentUser = $current_user;
-    $this->mapper = $mapper;
   }
 
   /**
diff --git a/src/Plugin/views/filter/PrivateMessageThreadCleanHistory.php b/src/Plugin/views/filter/PrivateMessageThreadCleanHistory.php
index 5f87cc68..de070afd 100644
--- a/src/Plugin/views/filter/PrivateMessageThreadCleanHistory.php
+++ b/src/Plugin/views/filter/PrivateMessageThreadCleanHistory.php
@@ -16,33 +16,14 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 class PrivateMessageThreadCleanHistory extends FilterPluginBase {
 
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountInterface
-   */
-  protected $currentUser;
-
-  /**
-   * Views Handler Plugin Manager.
-   *
-   * @var \Drupal\views\Plugin\ViewsHandlerManager
-   */
-  protected $joinHandler;
-
-  /**
-   * Creates an instance of PrivateMessageThreadCleanHistory.
-   */
   public function __construct(
     array $configuration,
     $plugin_id,
     $plugin_definition,
-    AccountInterface $current_user,
-    ViewsHandlerManager $join_handler,
+    protected readonly AccountInterface $currentUser,
+    protected readonly ViewsHandlerManager $joinHandler,
   ) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
-    $this->currentUser = $current_user;
-    $this->joinHandler = $join_handler;
   }
 
   /**
diff --git a/src/Plugin/views/filter/PrivateMessageThreadIsUnread.php b/src/Plugin/views/filter/PrivateMessageThreadIsUnread.php
index f05dd22f..d05b75d0 100644
--- a/src/Plugin/views/filter/PrivateMessageThreadIsUnread.php
+++ b/src/Plugin/views/filter/PrivateMessageThreadIsUnread.php
@@ -16,33 +16,14 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 class PrivateMessageThreadIsUnread extends FilterPluginBase {
 
-  /**
-   * The current user.
-   *
-   * @var \Drupal\Core\Session\AccountInterface
-   */
-  protected $currentUser;
-
-  /**
-   * Views Handler Plugin Manager.
-   *
-   * @var \Drupal\views\Plugin\ViewsHandlerManager
-   */
-  protected $joinHandler;
-
-  /**
-   * Creates an instance of PrivateMessageThreadCleanHistory.
-   */
   public function __construct(
     array $configuration,
     $plugin_id,
     $plugin_definition,
-    AccountInterface $current_user,
-    ViewsHandlerManager $join_handler,
+    protected readonly AccountInterface $currentUser,
+    protected readonly ViewsHandlerManager $joinHandler,
   ) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
-    $this->currentUser = $current_user;
-    $this->joinHandler = $join_handler;
   }
 
   /**
diff --git a/src/PluginManager/PrivateMessageConfigFormManagerInterface.php b/src/PluginManager/PrivateMessageConfigFormManagerInterface.php
index 6c79a74f..eb139b64 100644
--- a/src/PluginManager/PrivateMessageConfigFormManagerInterface.php
+++ b/src/PluginManager/PrivateMessageConfigFormManagerInterface.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\PluginManager;
 
 /**
diff --git a/src/Traits/PrivateMessageSettingsTrait.php b/src/Traits/PrivateMessageSettingsTrait.php
index e74e4922..4201c2f0 100644
--- a/src/Traits/PrivateMessageSettingsTrait.php
+++ b/src/Traits/PrivateMessageSettingsTrait.php
@@ -22,7 +22,7 @@ trait PrivateMessageSettingsTrait {
    * @return \Drupal\Core\Config\ImmutableConfig
    *   The private message module settings.
    */
-  protected function getSettings(): ImmutableConfig {
+  protected function getPrivateMessageSettings(): ImmutableConfig {
     assert(property_exists($this, 'configFactory'));
     if (!isset($this->privateMessageSettings)) {
       $this->privateMessageSettings = $this->configFactory->get('private_message.settings');
diff --git a/tests/src/Kernel/EntityDeleteTest.php b/tests/src/Kernel/EntityDeleteTest.php
index 7c7ef235..be7e603c 100644
--- a/tests/src/Kernel/EntityDeleteTest.php
+++ b/tests/src/Kernel/EntityDeleteTest.php
@@ -8,12 +8,12 @@ use Drupal\KernelTests\KernelTestBase;
 use Drupal\Tests\private_message\Traits\PrivateMessageTestTrait;
 use Drupal\private_message\Entity\PrivateMessageBan;
 use Drupal\private_message\Entity\PrivateMessageThreadInterface;
-use PHPUnit\Framework\Attributes\Group;
 
 /**
  * Tests deletion of private message entities.
+ *
+ * @group private_message
  */
-#[Group('private_message')]
 final class EntityDeleteTest extends KernelTestBase {
 
   use PrivateMessageTestTrait;
-- 
GitLab


From 3b0b2f70cd41f910b8b1092b2fd46e3bd33ae65f Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Wed, 27 Nov 2024 18:58:56 +0200
Subject: [PATCH 06/30] Attribute for PrivateMessageConfigForm plugins

---
 src/Attribute/PrivateMessageConfigForm.php    | 29 +++++++++++++++++++
 .../PrivateMessageConfigFormManager.php       | 18 ++++++++++--
 2 files changed, 44 insertions(+), 3 deletions(-)
 create mode 100644 src/Attribute/PrivateMessageConfigForm.php

diff --git a/src/Attribute/PrivateMessageConfigForm.php b/src/Attribute/PrivateMessageConfigForm.php
new file mode 100644
index 00000000..21d39499
--- /dev/null
+++ b/src/Attribute/PrivateMessageConfigForm.php
@@ -0,0 +1,29 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\private_message\Attribute;
+
+use Drupal\Component\Plugin\Attribute\Plugin;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+/**
+ * The private message configuration form plugin attribute.
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+class PrivateMessageConfigForm extends Plugin {
+
+  /**
+   * Constructs a PrivateMessageConfigForm attribute.
+   *
+   * @param string $id
+   *   The plugin ID.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup $name
+   *   The name of the form plugin.
+   */
+  public function __construct(
+    public readonly string $id,
+    public readonly TranslatableMarkup $name,
+  ) {}
+
+}
diff --git a/src/PluginManager/PrivateMessageConfigFormManager.php b/src/PluginManager/PrivateMessageConfigFormManager.php
index 19582c19..aa4a5cb6 100644
--- a/src/PluginManager/PrivateMessageConfigFormManager.php
+++ b/src/PluginManager/PrivateMessageConfigFormManager.php
@@ -7,7 +7,8 @@ namespace Drupal\private_message\PluginManager;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
-use Drupal\private_message\Annotation\PrivateMessageConfigForm;
+use Drupal\private_message\Annotation\PrivateMessageConfigForm as PrivateMessageConfigFormAnnotation;
+use Drupal\private_message\Attribute\PrivateMessageConfigForm as PrivateMessageConfigFormAttribute;
 use Drupal\private_message\Plugin\PrivateMessageConfigForm\PrivateMessageConfigFormPluginInterface;
 
 /**
@@ -15,8 +16,19 @@ use Drupal\private_message\Plugin\PrivateMessageConfigForm\PrivateMessageConfigF
  */
 class PrivateMessageConfigFormManager extends DefaultPluginManager implements PrivateMessageConfigFormManagerInterface {
 
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cacheBackend, ModuleHandlerInterface $moduleHandler) {
-    parent::__construct('Plugin/PrivateMessageConfigForm', $namespaces, $moduleHandler, PrivateMessageConfigFormPluginInterface::class, PrivateMessageConfigForm::class);
+  public function __construct(
+    \Traversable $namespaces,
+    CacheBackendInterface $cacheBackend,
+    ModuleHandlerInterface $moduleHandler,
+  ) {
+    parent::__construct(
+      'Plugin/PrivateMessageConfigForm',
+      $namespaces,
+      $moduleHandler,
+      PrivateMessageConfigFormPluginInterface::class,
+      PrivateMessageConfigFormAttribute::class,
+      PrivateMessageConfigFormAnnotation::class,
+    );
     $this->alterInfo('private_message_config_form_info');
     $this->setCacheBackend($cacheBackend, 'private_message_config_form');
   }
-- 
GitLab


From cc55d069389cfd0d2bc000f79b0a10b7b8124d49 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Wed, 27 Nov 2024 20:02:29 +0200
Subject: [PATCH 07/30] Convert to attributes where applicable

---
 .../Block/PrivateMessageActionsBlock.php      | 13 +++---
 src/Plugin/Block/PrivateMessageInboxBlock.php | 13 +++---
 .../Block/PrivateMessageNotificationBlock.php | 13 +++---
 .../PrivateMessageThreadMemberFormatter.php   | 17 +++----
 ...ateMessageThreadMembersNumberFormatter.php | 17 +++----
 .../PrivateMessageThreadMessageFormatter.php  | 17 +++----
 src/Plugin/RulesAction/SendPrivateMessage.php | 45 ++++++++++---------
 .../PrivateMessageThreadMemberConstraint.php  | 16 ++++---
 .../Constraint/UniqueBanConstraint.php        | 16 ++++---
 .../PrivateMessageThreadHasNewMessage.php     |  4 +-
 .../PrivateMessageThreadMessagesCount.php     |  4 +-
 .../PrivateMessageThreadNewMessagesCount.php  |  4 +-
 .../PrivateMessageThreadCleanHistory.php      |  4 +-
 .../filter/PrivateMessageThreadIsUnread.php   |  4 +-
 14 files changed, 101 insertions(+), 86 deletions(-)

diff --git a/src/Plugin/Block/PrivateMessageActionsBlock.php b/src/Plugin/Block/PrivateMessageActionsBlock.php
index 6d2906e5..d19ee209 100644
--- a/src/Plugin/Block/PrivateMessageActionsBlock.php
+++ b/src/Plugin/Block/PrivateMessageActionsBlock.php
@@ -4,11 +4,13 @@ namespace Drupal\private_message\Plugin\Block;
 
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Access\AccessResultInterface;
+use Drupal\Core\Block\Attribute\Block;
 use Drupal\Core\Block\BlockBase;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\AccountProxyInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -16,13 +18,12 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  * Provides the private message actions block.
  *
  * This block holds links to perform actions on a private message thread.
- *
- * @Block(
- *   id = "private_message_actions_block",
- *   admin_label = @Translation("Private Message Actions"),
- *   category =  @Translation("Private Message"),
- * )
  */
+#[Block(
+  id: 'private_message_actions_block',
+  admin_label: new TranslatableMarkup('Private Message Actions'),
+  category: new TranslatableMarkup('Private Message'),
+)]
 class PrivateMessageActionsBlock extends BlockBase implements ContainerFactoryPluginInterface {
 
   public function __construct(
diff --git a/src/Plugin/Block/PrivateMessageInboxBlock.php b/src/Plugin/Block/PrivateMessageInboxBlock.php
index 59746b67..4aa05288 100644
--- a/src/Plugin/Block/PrivateMessageInboxBlock.php
+++ b/src/Plugin/Block/PrivateMessageInboxBlock.php
@@ -5,6 +5,7 @@ namespace Drupal\private_message\Plugin\Block;
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Access\CsrfTokenGenerator;
+use Drupal\Core\Block\Attribute\Block;
 use Drupal\Core\Block\BlockBase;
 use Drupal\Core\Block\BlockPluginInterface;
 use Drupal\Core\Cache\Cache;
@@ -14,6 +15,7 @@ use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\AccountProxyInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
 use Drupal\private_message\Service\PrivateMessageServiceInterface;
 use Drupal\private_message\Traits\PrivateMessageSettingsTrait;
@@ -21,13 +23,12 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Provides the private message inbox block.
- *
- * @Block(
- *   id = "private_message_inbox_block",
- *   admin_label = @Translation("Private Message Inbox"),
- *   category =  @Translation("Private Message"),
- * )
  */
+#[Block(
+  id: 'private_message_inbox_block',
+  admin_label: new TranslatableMarkup('Private Message Inbox'),
+  category: new TranslatableMarkup('Private Message'),
+ )]
 class PrivateMessageInboxBlock extends BlockBase implements BlockPluginInterface, ContainerFactoryPluginInterface {
 
   use PrivateMessageSettingsTrait;
diff --git a/src/Plugin/Block/PrivateMessageNotificationBlock.php b/src/Plugin/Block/PrivateMessageNotificationBlock.php
index daa72055..99ace3c4 100644
--- a/src/Plugin/Block/PrivateMessageNotificationBlock.php
+++ b/src/Plugin/Block/PrivateMessageNotificationBlock.php
@@ -5,6 +5,7 @@ namespace Drupal\private_message\Plugin\Block;
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Access\CsrfTokenGenerator;
+use Drupal\Core\Block\Attribute\Block;
 use Drupal\Core\Block\BlockBase;
 use Drupal\Core\Block\BlockPluginInterface;
 use Drupal\Core\Cache\Cache;
@@ -13,6 +14,7 @@ use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\AccountProxyInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
 use Drupal\private_message\Service\PrivateMessageServiceInterface;
 use Drupal\private_message\Traits\PrivateMessageSettingsTrait;
@@ -20,13 +22,12 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Provides the private message notification block.
- *
- * @Block(
- *   id = "private_message_notification_block",
- *   admin_label = @Translation("Private Message Notification"),
- *   category =  @Translation("Private Message"),
- * )
  */
+#[Block(
+   id: "private_message_notification_block",
+   admin_label: new TranslatableMarkup('Private Message Notification'),
+   category:  new TranslatableMarkup('Private Message'),
+)]
 class PrivateMessageNotificationBlock extends BlockBase implements BlockPluginInterface, ContainerFactoryPluginInterface {
 
   use PrivateMessageSettingsTrait;
diff --git a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMemberFormatter.php b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMemberFormatter.php
index b1dc5d96..f1b7e6ea 100644
--- a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMemberFormatter.php
+++ b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMemberFormatter.php
@@ -5,6 +5,7 @@ namespace Drupal\private_message\Plugin\Field\FieldFormatter;
 use Drupal\Component\Render\FormattableMarkup;
 use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Field\Attribute\FieldFormatter;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\FormatterBase;
@@ -12,20 +13,20 @@ use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Render\RendererInterface;
 use Drupal\Core\Session\AccountProxyInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Defines the private message member field formatter.
- *
- * @FieldFormatter(
- *   id = "private_message_thread_member_formatter",
- *   label = @Translation("Private Message Thread Members"),
- *   field_types = {
- *     "entity_reference"
- *   },
- * )
  */
+#[FieldFormatter(
+  id: 'private_message_thread_member_formatter',
+  label: new TranslatableMarkup('Private Message Thread Members'),
+  field_types: [
+    'entity_reference',
+  ],
+)]
 class PrivateMessageThreadMemberFormatter extends FormatterBase implements ContainerFactoryPluginInterface {
 
   public function __construct(
diff --git a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMembersNumberFormatter.php b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMembersNumberFormatter.php
index 5f1548bf..746d9968 100644
--- a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMembersNumberFormatter.php
+++ b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMembersNumberFormatter.php
@@ -2,23 +2,24 @@
 
 namespace Drupal\private_message\Plugin\Field\FieldFormatter;
 
+use Drupal\Core\Field\Attribute\FieldFormatter;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\FormatterBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Defines the private message member field formatter.
- *
- * @FieldFormatter(
- *   id = "private_message_thread_members_number_formatter",
- *   label = @Translation("Private Message Thread Members Number"),
- *   field_types = {
- *     "entity_reference"
- *   },
- * )
  */
+#[FieldFormatter(
+  id: 'private_message_thread_members_number_formatter',
+  label: new TranslatableMarkup('Private Message Thread Members Number'),
+  field_types: [
+    'entity_reference',
+  ],
+)]
 class PrivateMessageThreadMembersNumberFormatter extends FormatterBase implements ContainerFactoryPluginInterface {
 
   /**
diff --git a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php
index ad42381d..3e8aac02 100644
--- a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php
+++ b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php
@@ -6,27 +6,28 @@ use Drupal\Core\Access\CsrfTokenGenerator;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Field\Attribute\FieldFormatter;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\FormatterBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Session\AccountProxyInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
 use Drupal\private_message\Traits\PrivateMessageSettingsTrait;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Defines the private message thread message field formatter.
- *
- * @FieldFormatter(
- *   id = "private_message_thread_message_formatter",
- *   label = @Translation("Private Message Messages"),
- *   field_types = {
- *     "entity_reference"
- *   }
- * )
  */
+#[FieldFormatter(
+  id: 'private_message_thread_message_formatter',
+  label: new TranslatableMarkup('Private Message Messages'),
+  field_types: [
+    'entity_reference',
+  ],
+)]
 class PrivateMessageThreadMessageFormatter extends FormatterBase implements ContainerFactoryPluginInterface {
 
   use PrivateMessageSettingsTrait;
diff --git a/src/Plugin/RulesAction/SendPrivateMessage.php b/src/Plugin/RulesAction/SendPrivateMessage.php
index 0fd6c7c7..81d2f120 100644
--- a/src/Plugin/RulesAction/SendPrivateMessage.php
+++ b/src/Plugin/RulesAction/SendPrivateMessage.php
@@ -3,35 +3,40 @@
 namespace Drupal\private_message\Plugin\RulesAction;
 
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\private_message\Entity\PrivateMessage;
 use Drupal\private_message\Service\PrivateMessageServiceInterface;
+use Drupal\rules\Context\ContextDefinition;
+use Drupal\rules\Core\Attribute\RulesAction;
 use Drupal\rules\Core\RulesActionBase;
 use Drupal\user\UserInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Provides "Send private message" rules action.
- *
- * @RulesAction(
- *   id = "private_message_send_message",
- *   label = @Translation("Send private message"),
- *   category = @Translation("System"),
- *   context_definitions = {
- *     "author" = @ContextDefinition("entity:user",
- *       label = @Translation("From"),
- *       description = @Translation("The author of the message.")
- *     ),
- *     "recipient" = @ContextDefinition("entity:user",
- *       label = @Translation("To"),
- *       description = @Translation("The recipient of the message.")
- *     ),
- *     "message" = @ContextDefinition("string",
- *       label = @Translation("Message"),
- *       description = @Translation("The message.")
- *     ),
- *   }
- * )
  */
+#[RulesAction(
+  id: 'private_message_send_message',
+  label: new TranslatableMarkup('Send private message'),
+  category: new TranslatableMarkup('System'),
+  context_definitions: [
+    'author' => new ContextDefinition(
+      data_type: 'entity:user',
+      label: new TranslatableMarkup('From'),
+      description: new TranslatableMarkup('The author of the message.')
+    ),
+    'recipient' => new ContextDefinition(
+      data_type: 'entity:user',
+      label: new TranslatableMarkup('To'),
+      description: new TranslatableMarkup('The recipient of the message.')
+    ),
+    'message' => new ContextDefinition(
+      data_type: 'string',
+      label: new TranslatableMarkup('Message'),
+      description: new TranslatableMarkup('The message.')
+    ),
+  ],
+)]
 class SendPrivateMessage extends RulesActionBase implements ContainerFactoryPluginInterface {
 
   public function __construct(
diff --git a/src/Plugin/Validation/Constraint/PrivateMessageThreadMemberConstraint.php b/src/Plugin/Validation/Constraint/PrivateMessageThreadMemberConstraint.php
index 9415a0d3..569b5b48 100644
--- a/src/Plugin/Validation/Constraint/PrivateMessageThreadMemberConstraint.php
+++ b/src/Plugin/Validation/Constraint/PrivateMessageThreadMemberConstraint.php
@@ -2,17 +2,19 @@
 
 namespace Drupal\private_message\Plugin\Validation\Constraint;
 
-use Symfony\Component\Validator\Constraint;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\Core\Validation\Attribute\Constraint;
+use Symfony\Component\Validator\Constraint as SymfonyConstraint;
 
 /**
  * Checks that members of the thread have permission to use private messages.
- *
- * @Constraint(
- *   id = "private_message_thread_member",
- *   label = @Translation("Private Message Thread Member", context = "Validation"),
- * )
  */
-class PrivateMessageThreadMemberConstraint extends Constraint {
+#[Constraint(
+  id: 'private_message_thread_member',
+  label: new TranslatableMarkup('Private Message Thread Member', [], ['context' => 'Validation']),
+)]
+class PrivateMessageThreadMemberConstraint extends SymfonyConstraint {
+
   /**
    * Constraint violation error.
    *
diff --git a/src/Plugin/Validation/Constraint/UniqueBanConstraint.php b/src/Plugin/Validation/Constraint/UniqueBanConstraint.php
index 787f6d2e..717dca28 100644
--- a/src/Plugin/Validation/Constraint/UniqueBanConstraint.php
+++ b/src/Plugin/Validation/Constraint/UniqueBanConstraint.php
@@ -2,17 +2,19 @@
 
 namespace Drupal\private_message\Plugin\Validation\Constraint;
 
-use Symfony\Component\Validator\Constraint;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\Core\Validation\Attribute\Constraint;
+use Symfony\Component\Validator\Constraint as SymfonyConstraint;
 
 /**
  * Validation constraint for unique bans.
- *
- * @Constraint(
- *   id = "UniquePrivateMessageBan",
- *   label = @Translation("Unique ban.", context = "Validation"),
- * )
  */
-class UniqueBanConstraint extends Constraint {
+#[Constraint(
+  id: 'UniquePrivateMessageBan',
+  label: new TranslatableMarkup('Unique ban', [], ['context' => 'Validation']),
+)]
+
+class UniqueBanConstraint extends SymfonyConstraint {
 
   /**
    * The default violation message.
diff --git a/src/Plugin/views/field/PrivateMessageThreadHasNewMessage.php b/src/Plugin/views/field/PrivateMessageThreadHasNewMessage.php
index f8527561..b400917e 100644
--- a/src/Plugin/views/field/PrivateMessageThreadHasNewMessage.php
+++ b/src/Plugin/views/field/PrivateMessageThreadHasNewMessage.php
@@ -4,6 +4,7 @@ namespace Drupal\private_message\Plugin\views\field;
 
 use Drupal\Core\Session\AccountInterface;
 use Drupal\private_message\Mapper\PrivateMessageMapperInterface;
+use Drupal\views\Attribute\ViewsField;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\ResultRow;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -12,9 +13,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  * Outputs thread new messages count.
  *
  * @ingroup views_field_handlers
- *
- * @ViewsField("private_message_thread_has_new_message_marker")
  */
+#[ViewsField("private_message_thread_has_new_message_marker")]
 class PrivateMessageThreadHasNewMessage extends FieldPluginBase {
 
   public function __construct(
diff --git a/src/Plugin/views/field/PrivateMessageThreadMessagesCount.php b/src/Plugin/views/field/PrivateMessageThreadMessagesCount.php
index c67accce..bbd4fbdc 100644
--- a/src/Plugin/views/field/PrivateMessageThreadMessagesCount.php
+++ b/src/Plugin/views/field/PrivateMessageThreadMessagesCount.php
@@ -3,6 +3,7 @@
 namespace Drupal\private_message\Plugin\views\field;
 
 use Drupal\Core\Session\AccountInterface;
+use Drupal\views\Attribute\ViewsField;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\ResultRow;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -11,9 +12,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  * Outputs thread messages count.
  *
  * @ingroup views_field_handlers
- *
- * @ViewsField("private_message_thread_all_messages_number")
  */
+#[ViewsField("private_message_thread_all_messages_number")]
 class PrivateMessageThreadMessagesCount extends FieldPluginBase {
 
   public function __construct(
diff --git a/src/Plugin/views/field/PrivateMessageThreadNewMessagesCount.php b/src/Plugin/views/field/PrivateMessageThreadNewMessagesCount.php
index 5c5d6228..79d47e64 100644
--- a/src/Plugin/views/field/PrivateMessageThreadNewMessagesCount.php
+++ b/src/Plugin/views/field/PrivateMessageThreadNewMessagesCount.php
@@ -4,6 +4,7 @@ namespace Drupal\private_message\Plugin\views\field;
 
 use Drupal\Core\Session\AccountInterface;
 use Drupal\private_message\Mapper\PrivateMessageMapperInterface;
+use Drupal\views\Attribute\ViewsField;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\ResultRow;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -12,9 +13,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  * Outputs thread new messages count.
  *
  * @ingroup views_field_handlers
- *
- * @ViewsField("private_message_thread_new_messages_count")
  */
+#[ViewsField("private_message_thread_new_messages_count")]
 class PrivateMessageThreadNewMessagesCount extends FieldPluginBase {
 
   public function __construct(
diff --git a/src/Plugin/views/filter/PrivateMessageThreadCleanHistory.php b/src/Plugin/views/filter/PrivateMessageThreadCleanHistory.php
index de070afd..3168e48a 100644
--- a/src/Plugin/views/filter/PrivateMessageThreadCleanHistory.php
+++ b/src/Plugin/views/filter/PrivateMessageThreadCleanHistory.php
@@ -3,6 +3,7 @@
 namespace Drupal\private_message\Plugin\views\filter;
 
 use Drupal\Core\Session\AccountInterface;
+use Drupal\views\Attribute\ViewsFilter;
 use Drupal\views\Plugin\ViewsHandlerManager;
 use Drupal\views\Plugin\views\filter\FilterPluginBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -11,9 +12,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  * Filters threads by the fact they are not cleared.
  *
  * @ingroup views_filter_handlers
- *
- * @ViewsFilter("private_message_thread_has_history")
  */
+#[ViewsFilter('private_message_thread_has_history')]
 class PrivateMessageThreadCleanHistory extends FilterPluginBase {
 
   public function __construct(
diff --git a/src/Plugin/views/filter/PrivateMessageThreadIsUnread.php b/src/Plugin/views/filter/PrivateMessageThreadIsUnread.php
index d05b75d0..dd7bfc32 100644
--- a/src/Plugin/views/filter/PrivateMessageThreadIsUnread.php
+++ b/src/Plugin/views/filter/PrivateMessageThreadIsUnread.php
@@ -3,6 +3,7 @@
 namespace Drupal\private_message\Plugin\views\filter;
 
 use Drupal\Core\Session\AccountInterface;
+use Drupal\views\Attribute\ViewsFilter;
 use Drupal\views\Plugin\ViewsHandlerManager;
 use Drupal\views\Plugin\views\filter\FilterPluginBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -11,9 +12,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  * Filters threads by the fact they are unread.
  *
  * @ingroup views_filter_handlers
- *
- * @ViewsFilter("private_message_thread_is_unread")
  */
+#[ViewsFilter('private_message_thread_is_unread')]
 class PrivateMessageThreadIsUnread extends FilterPluginBase {
 
   public function __construct(
-- 
GitLab


From 4d831096a0fda6283158142467a40904182b1b09 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Wed, 27 Nov 2024 20:10:22 +0200
Subject: [PATCH 08/30] Strict typing

---
 .../private_message_notify.module             |   4 +-
 .../src/Service/PrivateMessageNotifier.php    |   4 +-
 private_message.module                        |  42 +++---
 ...rivateMessageInboxInsertThreadsCommand.php |   2 +-
 ...rivateMessageInboxTriggerUpdateCommand.php |   2 +-
 src/Ajax/PrivateMessageInboxUpdateCommand.php |   2 +-
 ...rivateMessageInsertMessagesCommandBase.php |   2 +-
 ...teMessageInsertPreviousMessagesCommand.php |   2 +-
 .../PrivateMessageInsertThreadCommand.php     |   2 +-
 .../PrivateMessageLoadNewMessagesCommand.php  |   2 +-
 ...teMessageUpdateUnreadItemsCountCommand.php |   2 +-
 src/Annotation/PrivateMessageConfigForm.php   |  11 +-
 src/Attribute/PrivateMessageConfigForm.php    |   2 +-
 .../PrivateMessageThreadCacheContext.php      |   2 +
 src/Controller/AjaxController.php             | 122 ++++++++----------
 src/Controller/AjaxControllerInterface.php    |   6 +-
 src/Controller/PrivateMessageController.php   |  12 +-
 .../PrivateMessageControllerInterface.php     |  25 +++-
 src/Drush/Commands/PrivateMessageCommands.php |   2 +
 .../PrivateMessageAccessControlHandler.php    |   8 +-
 .../PrivateMessageBanAccessControlHandler.php |   9 +-
 ...ivateMessageThreadAccessControlHandler.php |  15 ++-
 .../Builder/PrivateMessageBanListBuilder.php  |   6 +-
 .../PrivateMessageThreadViewBuilder.php       |   5 +-
 .../Builder/PrivateMessageViewBuilder.php     |   7 +-
 25 files changed, 165 insertions(+), 133 deletions(-)

diff --git a/modules/private_message_notify/private_message_notify.module b/modules/private_message_notify/private_message_notify.module
index 93b8b838..b70f1db1 100644
--- a/modules/private_message_notify/private_message_notify.module
+++ b/modules/private_message_notify/private_message_notify.module
@@ -5,13 +5,15 @@
  * Primary module hooks for Private Message Notify module.
  */
 
+declare(strict_types=1);
+
 use Drupal\private_message\Entity\PrivateMessageInterface;
 use Drupal\private_message\Entity\PrivateMessageThreadInterface;
 
 /**
  * Implements hook_private_message_new_message().
  */
-function private_message_notify_private_message_new_message(PrivateMessageInterface $privateMessage, PrivateMessageThreadInterface $thread) {
+function private_message_notify_private_message_new_message(PrivateMessageInterface $privateMessage, PrivateMessageThreadInterface $thread): void {
   /** @var \Drupal\private_message_notify\Service\PrivateMessageNotifierInterface $notifier */
   $notifier = \Drupal::service('private_message_notify.notifier');
   $notifier->notify($privateMessage, $thread);
diff --git a/modules/private_message_notify/src/Service/PrivateMessageNotifier.php b/modules/private_message_notify/src/Service/PrivateMessageNotifier.php
index 67c19183..cde6646b 100644
--- a/modules/private_message_notify/src/Service/PrivateMessageNotifier.php
+++ b/modules/private_message_notify/src/Service/PrivateMessageNotifier.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message_notify\Service;
 
 use Drupal\Core\Config\ConfigFactoryInterface;
@@ -38,7 +40,7 @@ class PrivateMessageNotifier implements PrivateMessageNotifierInterface {
   /**
    * {@inheritdoc}
    */
-  public function notify(PrivateMessageInterface $message, PrivateMessageThreadInterface $thread) {
+  public function notify(PrivateMessageInterface $message, PrivateMessageThreadInterface $thread): void {
     $members = $this->getNotificationRecipients($message, $thread);
 
     foreach ($members as $member) {
diff --git a/private_message.module b/private_message.module
index 0f4efb74..ff8979ac 100644
--- a/private_message.module
+++ b/private_message.module
@@ -5,6 +5,7 @@
  * Contains hooks for the private message module.
  */
 
+use Drupal\Component\Render\MarkupInterface;
 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormStateInterface;
@@ -17,7 +18,7 @@ use Drupal\user\Entity\User;
 /**
  * Implements hook_views_data().
  */
-function private_message_views_data() {
+function private_message_views_data(): array {
   $data['private_message_threads']['has_history'] = [
     'title' => t('Clean history'),
     'group' => t('Private Message Thread'),
@@ -86,7 +87,7 @@ function private_message_views_data() {
 /**
  * Implements hook_entity_extra_field_info().
  */
-function private_message_entity_extra_field_info() {
+function private_message_entity_extra_field_info(): array {
   $fields = [];
 
   $private_message_thread_bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo('private_message_thread');
@@ -206,7 +207,7 @@ function private_message_entity_extra_field_info() {
  *
  * @see hook_entity_view()
  */
-function private_message_private_message_thread_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
+function private_message_private_message_thread_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, string $view_mode): void {
   if ($display->getComponent('last_message')) {
     $messages = $entity->getMessages();
     if ($messages) {
@@ -276,8 +277,7 @@ function private_message_private_message_thread_view(array &$build, EntityInterf
  *
  * @see hook_entity_view()
  */
-function private_message_user_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
-
+function private_message_user_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, string $view_mode): void {
   if ($display->getComponent('linked_username')) {
     if (\Drupal::currentUser()->hasPermission('access user profiles')) {
       $url = Url::fromRoute('entity.user.canonical', ['user' => $entity->id()]);
@@ -347,7 +347,7 @@ function private_message_user_view(array &$build, EntityInterface $entity, Entit
  *
  * @see hook_entity_view()
  */
-function private_message_node_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
+function private_message_node_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, string $view_mode): void {
   \Drupal::service('private_message.service')->createRenderablePrivateMessageThreadLink($build, $entity, $display, $view_mode);
 }
 
@@ -358,7 +358,7 @@ function private_message_node_view(array &$build, EntityInterface $entity, Entit
  *
  * @see hook_entity_view()
  */
-function private_message_comment_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
+function private_message_comment_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, string $view_mode): void {
   \Drupal::service('private_message.service')->createRenderablePrivateMessageThreadLink($build, $entity, $display, $view_mode);
 }
 
@@ -369,14 +369,14 @@ function private_message_comment_view(array &$build, EntityInterface $entity, En
  *
  * @see hook_entity_view()
  */
-function private_message_profile_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
+function private_message_profile_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, string $view_mode): void {
   \Drupal::service('private_message.service')->createRenderablePrivateMessageThreadLink($build, $entity, $display, $view_mode);
 }
 
 /**
  * Implements hook_form_alter().
  */
-function private_message_form_alter(&$form, FormStateInterface $formState, $form_id) {
+function private_message_form_alter(array &$form, FormStateInterface $formState, string $form_id): void {
   // Act on any implementation of the private message entity form. This form
   // can potentially exist multiple times on a page, so the form ID will be
   // dynamic in such a case.
@@ -403,8 +403,7 @@ function private_message_form_alter(&$form, FormStateInterface $formState, $form
  *
  * @see hook_form_alter()
  */
-function private_message_form_user_form_alter(array &$form, FormStateInterface $formState) {
-
+function private_message_form_user_form_alter(array &$form, FormStateInterface $formState): void {
   $config = \Drupal::config('private_message.settings');
 
   // Get the user whose account is being modified.
@@ -503,7 +502,7 @@ function private_message_form_user_form_alter(array &$form, FormStateInterface $
  *
  * @see private_message_form_user_form_alter()
  */
-function private_message_user_form_submit(array &$form, FormStateInterface $formState) {
+function private_message_user_form_submit(array &$form, FormStateInterface $formState): void {
   // Get the user whose account object is being modified.
   $user = $formState->getFormObject()->getEntity();
   $user_data = \Drupal::service('user.data');
@@ -525,7 +524,7 @@ function private_message_user_form_submit(array &$form, FormStateInterface $form
 /**
  * Implements hook_theme().
  */
-function private_message_theme() {
+function private_message_theme(): array {
   return [
     'private_message_thread' => [
       'render element' => 'elements',
@@ -557,7 +556,7 @@ function private_message_theme() {
  *   - private_message_thread: The private message thread object.
  *   - view_mode: View mode; e.g., 'full', 'teaser', etc.
  */
-function template_preprocess_private_message_thread(array &$variables) {
+function template_preprocess_private_message_thread(array &$variables): void {
   $variables['view_mode'] = $variables['elements']['#view_mode'];
   // Provide a distinct $teaser boolean.
   $variables['private_message_thread'] = $variables['elements']['#private_message_thread'];
@@ -587,7 +586,7 @@ function template_preprocess_private_message_thread(array &$variables) {
  *   - private_message: The private message object.
  *   - view_mode: View mode; e.g., 'full', 'teaser', etc.
  */
-function template_preprocess_private_message(array &$variables) {
+function template_preprocess_private_message(array &$variables): void {
   $variables['view_mode'] = $variables['elements']['#view_mode'];
   // Provide a distinct $teaser boolean.
   $variables['private_message'] = $variables['elements']['#private_message'];
@@ -608,7 +607,7 @@ function template_preprocess_private_message(array &$variables) {
 /**
  * Implements hook_help().
  */
-function private_message_help($route_name, RouteMatchInterface $route_match) {
+function private_message_help($route_name, RouteMatchInterface $route_match): string|array|MarkupInterface {
   switch ($route_name) {
     case 'help.page.private_message':
       return t(
@@ -619,6 +618,7 @@ function private_message_help($route_name, RouteMatchInterface $route_match) {
         ]
       );
   }
+  return [];
 }
 
 /**
@@ -628,7 +628,7 @@ function private_message_help($route_name, RouteMatchInterface $route_match) {
  * may be altered in themes/templates, and therefore should not be depended
  * upon.
  */
-function private_message_preprocess_field__private_message_thread__private_messages(&$vars) {
+function private_message_preprocess_field__private_message_thread__private_messages(array &$vars): void {
   foreach (array_keys($vars['items']) as $index) {
     $vars['items'][$index]['attributes']->setAttribute('class', 'private-message-wrapper');
   }
@@ -641,7 +641,7 @@ function private_message_preprocess_field__private_message_thread__private_messa
  * classes may be altered in themes/templates, and therefore should not be
  * depended upon.
  */
-function private_message_preprocess_container(&$vars) {
+function private_message_preprocess_container(array &$vars): void {
   if (!empty($vars['element']['#id'])) {
     if (str_starts_with($vars['element']['#id'], 'edit-members-wrapper')) {
       // Add a custom class to the private message members widget container.
@@ -659,7 +659,7 @@ function private_message_preprocess_container(&$vars) {
  *
  * Swaps out tokens with values.
  */
-function private_message_message_view_alter(array &$build) {
+function private_message_message_view_alter(array &$build): void {
   if ($build['#message']->bundle() == 'private_message_notification') {
     $data = [
       'private_message' => $build['#message']->get('field_message_private_message')->entity,
@@ -679,13 +679,13 @@ function private_message_message_view_alter(array &$build) {
 /**
  * Implements hook_suggestions_HOOK_alter().
  */
-function private_message_theme_suggestions_private_message_thread_alter(&$suggestions, &$vars) {
+function private_message_theme_suggestions_private_message_thread_alter(array &$suggestions, array &$vars): void {
   $suggestions[] = 'private_message_thread__' . $vars['elements']['#view_mode'];
 }
 
 /**
  * Implements hook_suggestions_HOOK_alter().
  */
-function private_message_theme_suggestions_private_message_alter(&$suggestions, &$vars) {
+function private_message_theme_suggestions_private_message_alter(array &$suggestions, array &$vars): void {
   $suggestions[] = 'private_message__' . $vars['elements']['#view_mode'];
 }
diff --git a/src/Ajax/PrivateMessageInboxInsertThreadsCommand.php b/src/Ajax/PrivateMessageInboxInsertThreadsCommand.php
index 669ced29..7aec9232 100644
--- a/src/Ajax/PrivateMessageInboxInsertThreadsCommand.php
+++ b/src/Ajax/PrivateMessageInboxInsertThreadsCommand.php
@@ -21,7 +21,7 @@ class PrivateMessageInboxInsertThreadsCommand implements CommandInterface {
   /**
    * {@inheritdoc}
    */
-  public function render() {
+  public function render(): array {
     return [
       'command' => 'insertInboxOldPrivateMessageThreads',
       'threads' => (string) $this->threads,
diff --git a/src/Ajax/PrivateMessageInboxTriggerUpdateCommand.php b/src/Ajax/PrivateMessageInboxTriggerUpdateCommand.php
index 572b9a0b..bfac8d88 100644
--- a/src/Ajax/PrivateMessageInboxTriggerUpdateCommand.php
+++ b/src/Ajax/PrivateMessageInboxTriggerUpdateCommand.php
@@ -14,7 +14,7 @@ class PrivateMessageInboxTriggerUpdateCommand implements CommandInterface {
   /**
    * {@inheritdoc}
    */
-  public function render() {
+  public function render(): array {
     return [
       'command' => 'privateMessageTriggerInboxUpdate',
     ];
diff --git a/src/Ajax/PrivateMessageInboxUpdateCommand.php b/src/Ajax/PrivateMessageInboxUpdateCommand.php
index b2910f15..c2e2c5a5 100644
--- a/src/Ajax/PrivateMessageInboxUpdateCommand.php
+++ b/src/Ajax/PrivateMessageInboxUpdateCommand.php
@@ -28,7 +28,7 @@ class PrivateMessageInboxUpdateCommand implements CommandInterface {
   /**
    * {@inheritdoc}
    */
-  public function render() {
+  public function render(): array {
     return [
       'command' => 'privateMessageInboxUpdate',
       'threadIds' => $this->threadIds,
diff --git a/src/Ajax/PrivateMessageInsertMessagesCommandBase.php b/src/Ajax/PrivateMessageInsertMessagesCommandBase.php
index 7007f226..6bb0d238 100644
--- a/src/Ajax/PrivateMessageInsertMessagesCommandBase.php
+++ b/src/Ajax/PrivateMessageInsertMessagesCommandBase.php
@@ -30,7 +30,7 @@ abstract class PrivateMessageInsertMessagesCommandBase implements CommandInterfa
   /**
    * {@inheritdoc}
    */
-  public function render() {
+  public function render(): array {
     return [
       'command' => 'insertPrivateMessages',
       'insertType' => $this->insertType,
diff --git a/src/Ajax/PrivateMessageInsertPreviousMessagesCommand.php b/src/Ajax/PrivateMessageInsertPreviousMessagesCommand.php
index 9bf102e4..5efeeff8 100644
--- a/src/Ajax/PrivateMessageInsertPreviousMessagesCommand.php
+++ b/src/Ajax/PrivateMessageInsertPreviousMessagesCommand.php
@@ -30,7 +30,7 @@ class PrivateMessageInsertPreviousMessagesCommand extends PrivateMessageInsertMe
   /**
    * {@inheritdoc}
    */
-  public function render() {
+  public function render(): array {
     $return = parent::render();
     $return['hasNext'] = $this->hasNext;
     return $return;
diff --git a/src/Ajax/PrivateMessageInsertThreadCommand.php b/src/Ajax/PrivateMessageInsertThreadCommand.php
index 122ac58a..52a28911 100644
--- a/src/Ajax/PrivateMessageInsertThreadCommand.php
+++ b/src/Ajax/PrivateMessageInsertThreadCommand.php
@@ -16,7 +16,7 @@ class PrivateMessageInsertThreadCommand implements CommandInterface {
   /**
    * {@inheritdoc}
    */
-  public function render() {
+  public function render(): array {
     return [
       'command' => 'privateMessageInsertThread',
       'thread' => $this->threadHtml,
diff --git a/src/Ajax/PrivateMessageLoadNewMessagesCommand.php b/src/Ajax/PrivateMessageLoadNewMessagesCommand.php
index b7771fa9..f64ca2c1 100644
--- a/src/Ajax/PrivateMessageLoadNewMessagesCommand.php
+++ b/src/Ajax/PrivateMessageLoadNewMessagesCommand.php
@@ -14,7 +14,7 @@ class PrivateMessageLoadNewMessagesCommand implements CommandInterface {
   /**
    * {@inheritdoc}
    */
-  public function render() {
+  public function render(): array {
     return [
       'command' => 'loadNewPrivateMessages',
     ];
diff --git a/src/Ajax/PrivateMessageUpdateUnreadItemsCountCommand.php b/src/Ajax/PrivateMessageUpdateUnreadItemsCountCommand.php
index cc2af1cb..d1ab4719 100644
--- a/src/Ajax/PrivateMessageUpdateUnreadItemsCountCommand.php
+++ b/src/Ajax/PrivateMessageUpdateUnreadItemsCountCommand.php
@@ -19,7 +19,7 @@ class PrivateMessageUpdateUnreadItemsCountCommand implements CommandInterface {
   /**
    * {@inheritdoc}
    */
-  public function render() {
+  public function render(): array {
     return [
       'command' => 'privateMessageUpdateUnreadItemsCount',
       'unreadItemsCount' => $this->unreadThreadsCount,
diff --git a/src/Annotation/PrivateMessageConfigForm.php b/src/Annotation/PrivateMessageConfigForm.php
index fb288690..7d0d4feb 100644
--- a/src/Annotation/PrivateMessageConfigForm.php
+++ b/src/Annotation/PrivateMessageConfigForm.php
@@ -1,8 +1,11 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Annotation;
 
 use Drupal\Component\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
 
 /**
  * Annotation definition for the Private Message Configuration Form plugin.
@@ -13,18 +16,14 @@ class PrivateMessageConfigForm extends Plugin {
 
   /**
    * The plugin ID.
-   *
-   * @var string
    */
-  public $id;
+  public string $id;
 
   /**
    * The name of the form plugin.
    *
-   * @var \Drupal\Core\Annotation\Translation
-   *
    * @ingroup plugin_translatable
    */
-  public $name;
+  public Translation $name;
 
 }
diff --git a/src/Attribute/PrivateMessageConfigForm.php b/src/Attribute/PrivateMessageConfigForm.php
index 21d39499..1fae7d05 100644
--- a/src/Attribute/PrivateMessageConfigForm.php
+++ b/src/Attribute/PrivateMessageConfigForm.php
@@ -14,7 +14,7 @@ use Drupal\Core\StringTranslation\TranslatableMarkup;
 class PrivateMessageConfigForm extends Plugin {
 
   /**
-   * Constructs a PrivateMessageConfigForm attribute.
+   * Constructs a new PrivateMessageConfigForm attribute.
    *
    * @param string $id
    *   The plugin ID.
diff --git a/src/Cache/Context/PrivateMessageThreadCacheContext.php b/src/Cache/Context/PrivateMessageThreadCacheContext.php
index b65f71ef..bb81bb88 100644
--- a/src/Cache/Context/PrivateMessageThreadCacheContext.php
+++ b/src/Cache/Context/PrivateMessageThreadCacheContext.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Cache\Context;
 
 use Drupal\Core\Cache\CacheableMetadata;
diff --git a/src/Controller/AjaxController.php b/src/Controller/AjaxController.php
index c8b70dd5..3673ad5a 100644
--- a/src/Controller/AjaxController.php
+++ b/src/Controller/AjaxController.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Controller;
 
 use Drupal\Core\Ajax\AjaxResponse;
@@ -12,6 +14,7 @@ use Drupal\private_message\Ajax\PrivateMessageInsertNewMessagesCommand;
 use Drupal\private_message\Ajax\PrivateMessageInsertPreviousMessagesCommand;
 use Drupal\private_message\Ajax\PrivateMessageInsertThreadCommand;
 use Drupal\private_message\Ajax\PrivateMessageUpdateUnreadItemsCountCommand;
+use Drupal\private_message\Entity\PrivateMessageThreadInterface;
 use Drupal\private_message\Service\PrivateMessageServiceInterface;
 use Symfony\Component\HttpFoundation\RequestStack;
 
@@ -29,66 +32,33 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface {
   /**
    * {@inheritdoc}
    */
-  public function ajaxCallback($op) {
-    $response = new AjaxResponse();
-
-    switch ($op) {
-
-      case 'get_new_messages':
-        $this->getNewPrivateMessages($response);
-
-        break;
-
-      case 'get_old_messages':
-        $this->getOldPrivateMessages($response);
-
-        break;
-
-      case 'get_old_inbox_threads':
-        $this->getOldInboxThreads($response);
-
-        break;
-
-      case 'get_new_inbox_threads':
-        $this->getNewInboxThreads($response);
-
-        break;
-
-      case 'get_new_unread_thread_count':
-        $this->getNewUnreadThreadCount($response);
-
-        break;
-
-      case 'get_new_unread_message_count':
-        $this->getNewUnreadMessageCount($response);
-
-        break;
-
-      case 'load_thread':
-        $this->loadThread($response);
-
-        break;
-    }
-
-    return $response;
+  public function ajaxCallback(string $op): AjaxResponse {
+    return match($op) {
+      'get_new_messages' => $this->getNewPrivateMessages(),
+      'get_old_messages' => $this->getOldPrivateMessages(),
+      'get_old_inbox_threads' => $this->getOldInboxThreads(),
+      'get_new_inbox_threads' => $this->getNewInboxThreads(),
+      'get_new_unread_thread_count' => $this->getNewUnreadThreadCount(),
+      'get_new_unread_message_count' => $this->getNewUnreadMessageCount(),
+      'load_thread' => $this->loadThread(),
+    };
   }
 
   /**
    * Creates an Ajax Command containing new private message.
    *
-   * @param \Drupal\Core\Ajax\AjaxResponse $response
+   * @return \Drupal\Core\Ajax\AjaxResponse
    *   The response to which any commands should be attached.
    */
-  protected function getNewPrivateMessages(AjaxResponse $response) {
+  protected function getNewPrivateMessages(): AjaxResponse {
+    $response = new AjaxResponse();
     $thread_id = $this->requestStack->getCurrentRequest()->get('threadid');
     $message_id = $this->requestStack->getCurrentRequest()->get('messageid');
-    $count = 0;
+
     if (is_numeric($thread_id) && is_numeric($message_id)) {
-      /** @var \Drupal\private_message\Entity\PrivateMessageThreadInterface $thread */
-      $thread = $this->entityTypeManager()
-        ->getStorage('private_message_thread')
+      $thread = $this->entityTypeManager()->getStorage('private_message_thread')
         ->load($thread_id);
-      if ($thread) {
+      if ($thread instanceof PrivateMessageThreadInterface) {
         $new_messages = $this->privateMessageService->getNewMessages($thread_id, $message_id);
         $this->privateMessageService->updateThreadAccessTime($thread);
         $count = count($new_messages);
@@ -108,18 +78,22 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface {
           $messages['#attached']['drupalSettings']['privateMessageThread']['threadId'] = (int) $thread->id();
         }
 
-        $response->addCommand(new PrivateMessageInsertNewMessagesCommand($this->renderer->renderRoot($messages), $count));
+        $response->addCommand(new PrivateMessageInsertNewMessagesCommand((string) $this->renderer->renderRoot($messages), $count));
       }
     }
+
+    return $response;
   }
 
   /**
    * Create an Ajax Command containing old private messages.
    *
-   * @param \Drupal\Core\Ajax\AjaxResponse $response
+   * @return \Drupal\Core\Ajax\AjaxResponse
    *   The response to which any commands should be attached.
    */
-  protected function getOldPrivateMessages(AjaxResponse $response) {
+  protected function getOldPrivateMessages(): AjaxResponse {
+    $response = new AjaxResponse();
+
     $current_request = $this->requestStack->getCurrentRequest();
     $thread_id = $current_request->get('threadid');
     $message_id = $current_request->get('messageid');
@@ -139,21 +113,25 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface {
           }
         }
 
-        $response->addCommand(new PrivateMessageInsertPreviousMessagesCommand($this->renderer->renderRoot($messages), count($message_info['messages']), $has_next));
+        $response->addCommand(new PrivateMessageInsertPreviousMessagesCommand((string) $this->renderer->renderRoot($messages), count($message_info['messages']), $has_next));
       }
       else {
         $response->addCommand(new PrivateMessageInsertPreviousMessagesCommand('', 0, FALSE));
       }
     }
+
+    return $response;
   }
 
   /**
    * Creates and Ajax Command containing old threads for the inbox.
    *
-   * @param \Drupal\Core\Ajax\AjaxResponse $response
+   * @return \Drupal\Core\Ajax\AjaxResponse
    *   The response to which any commands should be attached.
    */
-  protected function getOldInboxThreads(AjaxResponse $response) {
+  protected function getOldInboxThreads(): AjaxResponse {
+    $response = new AjaxResponse();
+
     $timestamp = $this->requestStack->getCurrentRequest()->get('timestamp');
     $thread_count = $this->requestStack->getCurrentRequest()->get('count');
     if (is_numeric($timestamp)) {
@@ -174,15 +152,19 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface {
         $response->addCommand(new PrivateMessageInboxInsertThreadsCommand('', FALSE));
       }
     }
+
+    return $response;
   }
 
   /**
    * Creates an Ajax Command with new threads for the private message inbox.
    *
-   * @param \Drupal\Core\Ajax\AjaxResponse $response
+   * @return \Drupal\Core\Ajax\AjaxResponse
    *   The response to which any commands should be attached.
    */
-  protected function getNewInboxThreads(AjaxResponse $response) {
+  protected function getNewInboxThreads(): AjaxResponse {
+    $response = new AjaxResponse();
+
     $info = $this->requestStack->getCurrentRequest()->get('ids');
 
     // Check to see if any thread IDs were POSTed.
@@ -214,6 +196,8 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface {
       // Add the command that will tell the inbox which thread items to update.
       $response->addCommand(new PrivateMessageInboxUpdateCommand($inbox_threads['thread_ids'], $rendered_threads));
     }
+
+    return $response;
   }
 
   /**
@@ -222,13 +206,14 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface {
    * Only messages created since the current user last visited the private
    * message page are shown.
    *
-   * @param \Drupal\Core\Ajax\AjaxResponse $response
+   * @return \Drupal\Core\Ajax\AjaxResponse
    *   The response to which any commands should be attached.
    */
-  protected function getNewUnreadThreadCount(AjaxResponse $response) {
+  protected function getNewUnreadThreadCount(): AjaxResponse {
+    $response = new AjaxResponse();
     $unread_thread_count = $this->privateMessageService->getUnreadThreadCount();
-
     $response->addCommand(new PrivateMessageUpdateUnreadItemsCountCommand($unread_thread_count));
+    return $response;
   }
 
   /**
@@ -237,22 +222,25 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface {
    * Only messages created since the current user last visited the private
    * message page are shown.
    *
-   * @param \Drupal\Core\Ajax\AjaxResponse $response
+   * @return \Drupal\Core\Ajax\AjaxResponse
    *   The response to which any commands should be attached.
    */
-  protected function getNewUnreadMessageCount(AjaxResponse $response) {
+  protected function getNewUnreadMessageCount(): AjaxResponse {
+    $response = new AjaxResponse();
     $unread_message_count = $this->privateMessageService->getUnreadMessageCount();
-
     $response->addCommand(new PrivateMessageUpdateUnreadItemsCountCommand($unread_message_count));
+    return $response;
   }
 
   /**
    * Load a private message thread to be dynamically inserted into the page.
    *
-   * @param \Drupal\Core\Ajax\AjaxResponse $response
+   * @return \Drupal\Core\Ajax\AjaxResponse
    *   The response to which any commands should be attached.
    */
-  protected function loadThread(AjaxResponse $response) {
+  protected function loadThread(): AjaxResponse {
+    $response = new AjaxResponse();
+
     $thread_id = $this->requestStack->getCurrentRequest()->get('id');
     if ($thread_id) {
       $thread = $this->entityTypeManager()->getStorage('private_message_thread')->load($thread_id);
@@ -262,7 +250,7 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface {
 
         $view_builder = $this->entityTypeManager()->getViewBuilder('private_message_thread');
         $renderable = $view_builder->view($thread);
-        $rendered_thread = $this->renderer->renderRoot($renderable);
+        $rendered_thread = (string) $this->renderer->renderRoot($renderable);
 
         $response->addCommand(new SettingsCommand($renderable['#attached']['drupalSettings'], TRUE));
         $response->addCommand(new PrivateMessageInsertThreadCommand($rendered_thread));
@@ -270,6 +258,8 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface {
         $response->addCommand(new PrivateMessageUpdateUnreadItemsCountCommand($unread_thread_count));
       }
     }
+
+    return $response;
   }
 
 }
diff --git a/src/Controller/AjaxControllerInterface.php b/src/Controller/AjaxControllerInterface.php
index 9b72988e..978fdc39 100644
--- a/src/Controller/AjaxControllerInterface.php
+++ b/src/Controller/AjaxControllerInterface.php
@@ -1,7 +1,11 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Controller;
 
+use Drupal\Core\Ajax\AjaxResponse;
+
 /**
  * Interface for the Private Message module's AjaxController.
  */
@@ -16,6 +20,6 @@ interface AjaxControllerInterface {
    * @return \Drupal\Core\Ajax\AjaxResponse
    *   The ajax response
    */
-  public function ajaxCallback($op);
+  public function ajaxCallback(string $op): AjaxResponse;
 
 }
diff --git a/src/Controller/PrivateMessageController.php b/src/Controller/PrivateMessageController.php
index d7a8c459..8edb7796 100644
--- a/src/Controller/PrivateMessageController.php
+++ b/src/Controller/PrivateMessageController.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Controller;
 
 use Drupal\Core\Controller\ControllerBase;
@@ -22,7 +24,7 @@ class PrivateMessageController extends ControllerBase implements PrivateMessageC
   /**
    * {@inheritdoc}
    */
-  public function privateMessagePage() {
+  public function privateMessagePage(): array {
     $this->privateMessageService->updateLastCheckTime();
 
     /** @var \Drupal\user\UserInterface $user */
@@ -56,7 +58,7 @@ class PrivateMessageController extends ControllerBase implements PrivateMessageC
   /**
    * {@inheritdoc}
    */
-  public function pmSettingsPage() {
+  public function pmSettingsPage(): array {
     $url = Url::fromRoute('private_message.admin_config.config')->toString();
     $message = $this->t('You can find module settings here: <a href="@url">page</a>', ['@url' => $url]);
     return [
@@ -67,7 +69,7 @@ class PrivateMessageController extends ControllerBase implements PrivateMessageC
   /**
    * {@inheritdoc}
    */
-  public function pmThreadSettingsPage() {
+  public function pmThreadSettingsPage(): array {
     return [
       '#markup' => $this->t('Private Message Threads'),
     ];
@@ -76,7 +78,7 @@ class PrivateMessageController extends ControllerBase implements PrivateMessageC
   /**
    * {@inheritdoc}
    */
-  public function configPage() {
+  public function configPage(): array {
     return [
       '#prefix' => '<div id="private_message_configuration_page">',
       '#suffix' => '</div>',
@@ -87,7 +89,7 @@ class PrivateMessageController extends ControllerBase implements PrivateMessageC
   /**
    * {@inheritdoc}
    */
-  public function adminUninstallPage() {
+  public function adminUninstallPage(): array {
     return [
       'message' => [
         '#prefix' => '<div id="private_message_admin_uninstall_page">',
diff --git a/src/Controller/PrivateMessageControllerInterface.php b/src/Controller/PrivateMessageControllerInterface.php
index 05be08e1..d1e5ce1a 100644
--- a/src/Controller/PrivateMessageControllerInterface.php
+++ b/src/Controller/PrivateMessageControllerInterface.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Controller;
 
 /**
@@ -9,26 +11,41 @@ interface PrivateMessageControllerInterface {
 
   /**
    * The Private message page.
+   *
+   * @return array
+   *   Render array.
    */
-  public function privateMessagePage();
+  public function privateMessagePage(): array;
 
   /**
    * The private message module settings page.
+   *
+   * @return array
+   *   Render array.
    */
-  public function pmSettingsPage();
+  public function pmSettingsPage(): array;
 
   /**
    * The settings page specific to private message threads.
+   *
+   * @return array
+   *   Render array.
    */
-  public function pmThreadSettingsPage();
+  public function pmThreadSettingsPage(): array;
 
   /**
    * The page for preparing to uninstall the module.
+   *
+   * @return array
+   *   Render array.
    */
-  public function adminUninstallPage();
+  public function adminUninstallPage(): array;
 
   /**
    * The page for banning and unbanning users.
+   *
+   * @return array
+   *   Render array.
    */
   public function banUnbanPage(): array;
 
diff --git a/src/Drush/Commands/PrivateMessageCommands.php b/src/Drush/Commands/PrivateMessageCommands.php
index 868fa999..ae4377c1 100644
--- a/src/Drush/Commands/PrivateMessageCommands.php
+++ b/src/Drush/Commands/PrivateMessageCommands.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Drush\Commands;
 
 use Drupal\Core\DependencyInjection\AutowireTrait;
diff --git a/src/Entity/Access/PrivateMessageAccessControlHandler.php b/src/Entity/Access/PrivateMessageAccessControlHandler.php
index 7fe34d69..6985c23f 100644
--- a/src/Entity/Access/PrivateMessageAccessControlHandler.php
+++ b/src/Entity/Access/PrivateMessageAccessControlHandler.php
@@ -5,11 +5,13 @@ declare(strict_types=1);
 namespace Drupal\private_message\Entity\Access;
 
 use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Entity\EntityAccessControlHandler;
 use Drupal\Core\Entity\EntityHandlerInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\private_message\Entity\PrivateMessageInterface;
 use Drupal\private_message\Service\PrivateMessageServiceInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -41,7 +43,9 @@ class PrivateMessageAccessControlHandler extends EntityAccessControlHandler impl
    * Link the activities to the permissions. checkAccess is called with the
    * $operation as defined in the routing.yml file.
    */
-  protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
+  protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account): AccessResultInterface {
+    assert($entity instanceof PrivateMessageInterface);
+
     if ($account->hasPermission('use private messaging system')) {
       switch ($operation) {
         case 'view':
@@ -57,7 +61,6 @@ class PrivateMessageAccessControlHandler extends EntityAccessControlHandler impl
           if ($account->hasPermission('administer private messages')) {
             return AccessResult::allowed();
           }
-
           break;
 
         case 'delete':
@@ -70,7 +73,6 @@ class PrivateMessageAccessControlHandler extends EntityAccessControlHandler impl
           }
 
           return AccessResult::allowedIfHasPermission($account, 'delete any private message');
-
       }
     }
 
diff --git a/src/Entity/Access/PrivateMessageBanAccessControlHandler.php b/src/Entity/Access/PrivateMessageBanAccessControlHandler.php
index 07d8b9c3..adefdb80 100644
--- a/src/Entity/Access/PrivateMessageBanAccessControlHandler.php
+++ b/src/Entity/Access/PrivateMessageBanAccessControlHandler.php
@@ -5,9 +5,11 @@ declare(strict_types=1);
 namespace Drupal\private_message\Entity\Access;
 
 use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Entity\EntityAccessControlHandler;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\private_message\Entity\PrivateMessageBanInterface;
 
 /**
  * Access controller for the Private Message Ban entities.
@@ -19,8 +21,9 @@ class PrivateMessageBanAccessControlHandler extends EntityAccessControlHandler {
   /**
    * {@inheritdoc}
    */
-  protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
-    /** @var \Drupal\private_message\Entity\PrivateMessageBanInterface $entity */
+  protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account): AccessResultInterface {
+    assert($entity instanceof PrivateMessageBanInterface);
+
     switch ($operation) {
       case 'view':
         return AccessResult::allowedIfHasPermission($account, 'view private message ban entities');
@@ -39,7 +42,7 @@ class PrivateMessageBanAccessControlHandler extends EntityAccessControlHandler {
   /**
    * {@inheritdoc}
    */
-  protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
+  protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL): AccessResultInterface {
     return AccessResult::allowedIfHasPermission($account, 'add private message ban entities');
   }
 
diff --git a/src/Entity/Access/PrivateMessageThreadAccessControlHandler.php b/src/Entity/Access/PrivateMessageThreadAccessControlHandler.php
index 85cc6b88..d5a917d1 100644
--- a/src/Entity/Access/PrivateMessageThreadAccessControlHandler.php
+++ b/src/Entity/Access/PrivateMessageThreadAccessControlHandler.php
@@ -5,9 +5,11 @@ declare(strict_types=1);
 namespace Drupal\private_message\Entity\Access;
 
 use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Access\AccessResultInterface;
 use Drupal\Core\Entity\EntityAccessControlHandler;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\private_message\Entity\PrivateMessageThreadInterface;
 
 /**
  * Access control handler for private message thread entities.
@@ -17,7 +19,9 @@ class PrivateMessageThreadAccessControlHandler extends EntityAccessControlHandle
   /**
    * {@inheritdoc}
    */
-  protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
+  protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account): AccessResultInterface {
+    assert($entity instanceof PrivateMessageThreadInterface);
+
     if ($account->hasPermission('administer private messages')) {
       return AccessResult::allowed();
     }
@@ -31,17 +35,15 @@ class PrivateMessageThreadAccessControlHandler extends EntityAccessControlHandle
               return AccessResult::allowed();
             }
           }
-
           break;
 
         case 'delete':
-          // Allow delete if we are member of this thread
-          // And if we have permission to delete thread for everyone.
+          // Allow to delete if we are member of this thread and if we have
+          // permission to delete thread for everyone.
           if ($entity->isMember($account->id())
             && $account->hasPermission('delete private message thread for all')) {
             return AccessResult::allowed();
           }
-
           break;
 
         case 'clear_personal_history':
@@ -49,7 +51,6 @@ class PrivateMessageThreadAccessControlHandler extends EntityAccessControlHandle
           if ($entity->isMember($account->id())) {
             return AccessResult::allowed();
           }
-
           break;
       }
     }
@@ -63,7 +64,7 @@ class PrivateMessageThreadAccessControlHandler extends EntityAccessControlHandle
    * Separate from the checkAccess because the entity does not yet exist, it
    * will be created during the 'add' process.
    */
-  protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
+  protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL): AccessResultInterface {
     return AccessResult::allowedIfHasPermission($account, 'use private messaging system');
   }
 
diff --git a/src/Entity/Builder/PrivateMessageBanListBuilder.php b/src/Entity/Builder/PrivateMessageBanListBuilder.php
index 0d195bfe..6a6ca426 100644
--- a/src/Entity/Builder/PrivateMessageBanListBuilder.php
+++ b/src/Entity/Builder/PrivateMessageBanListBuilder.php
@@ -10,15 +10,13 @@ use Drupal\Core\Link;
 
 /**
  * Defines a class to build a listing of Private Message Ban entities.
- *
- * @ingroup private_message
  */
 class PrivateMessageBanListBuilder extends EntityListBuilder {
 
   /**
    * {@inheritdoc}
    */
-  public function buildHeader() {
+  public function buildHeader(): array {
     // @todo Make this useful by adding the ban owner and target fields.
     $header['id'] = $this->t('Private Message Ban ID');
     $header['name'] = $this->t('Name');
@@ -28,7 +26,7 @@ class PrivateMessageBanListBuilder extends EntityListBuilder {
   /**
    * {@inheritdoc}
    */
-  public function buildRow(EntityInterface $entity) {
+  public function buildRow(EntityInterface $entity): array {
     /** @var \Drupal\private_message\Entity\PrivateMessageBanInterface $entity */
     $row['id'] = $entity->id();
     $row['name'] = Link::createFromRoute(
diff --git a/src/Entity/Builder/PrivateMessageThreadViewBuilder.php b/src/Entity/Builder/PrivateMessageThreadViewBuilder.php
index 7e54df9e..ce32ab00 100644
--- a/src/Entity/Builder/PrivateMessageThreadViewBuilder.php
+++ b/src/Entity/Builder/PrivateMessageThreadViewBuilder.php
@@ -14,6 +14,7 @@ use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\Core\Theme\Registry;
 use Drupal\Core\Url;
+use Drupal\private_message\Entity\PrivateMessageThreadInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -35,7 +36,7 @@ class PrivateMessageThreadViewBuilder extends EntityViewBuilder {
   /**
    * {@inheritdoc}
    */
-  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type): PrivateMessageThreadViewBuilder {
+  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type): self {
     return new static(
       $entity_type,
       $container->get('entity.repository'),
@@ -50,6 +51,8 @@ class PrivateMessageThreadViewBuilder extends EntityViewBuilder {
    * {@inheritdoc}
    */
   public function view(EntityInterface $entity, $view_mode = 'full', $langcode = NULL): array {
+    assert($entity instanceof PrivateMessageThreadInterface);
+
     $build = parent::view($entity, $view_mode, $langcode);
 
     $classes = ['private-message-thread'];
diff --git a/src/Entity/Builder/PrivateMessageViewBuilder.php b/src/Entity/Builder/PrivateMessageViewBuilder.php
index a6d46f87..b2fa129a 100644
--- a/src/Entity/Builder/PrivateMessageViewBuilder.php
+++ b/src/Entity/Builder/PrivateMessageViewBuilder.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Entity\Builder;
 
 use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
@@ -10,6 +12,7 @@ use Drupal\Core\Entity\EntityViewBuilder;
 use Drupal\Core\Language\LanguageManagerInterface;
 use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\Core\Theme\Registry;
+use Drupal\private_message\Entity\PrivateMessageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -31,7 +34,7 @@ class PrivateMessageViewBuilder extends EntityViewBuilder {
   /**
    * {@inheritdoc}
    */
-  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type): PrivateMessageViewBuilder {
+  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type): self {
     return new static(
       $entity_type,
       $container->get('entity.repository'),
@@ -46,6 +49,8 @@ class PrivateMessageViewBuilder extends EntityViewBuilder {
    * {@inheritdoc}
    */
   public function view(EntityInterface $entity, $view_mode = 'default', $langcode = NULL): array {
+    assert($entity instanceof PrivateMessageInterface);
+
     $message = parent::view($entity, $view_mode, $langcode);
 
     $classes = ['private-message'];
-- 
GitLab


From af33c50999e7720ae6dd1c0149d70e96b69d6af6 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Wed, 27 Nov 2024 21:11:52 +0200
Subject: [PATCH 09/30] Update private_message entity type

---
 src/Entity/PrivateMessage.php          | 74 +++++++-------------------
 src/Entity/PrivateMessageInterface.php |  8 +--
 2 files changed, 24 insertions(+), 58 deletions(-)

diff --git a/src/Entity/PrivateMessage.php b/src/Entity/PrivateMessage.php
index 6928aa6f..7ccebcef 100644
--- a/src/Entity/PrivateMessage.php
+++ b/src/Entity/PrivateMessage.php
@@ -1,15 +1,16 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Entity;
 
 use Drupal\Core\Entity\ContentEntityBase;
-use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
-use Drupal\user\UserInterface;
+use Drupal\user\EntityOwnerTrait;
 
 /**
- * Thee Private Message entity definition.
+ * The Private Message entity definition.
  *
  * @ContentEntityType(
  *   id = "private_message",
@@ -28,7 +29,8 @@ use Drupal\user\UserInterface;
  *   fieldable = TRUE,
  *   entity_keys = {
  *     "id" = "id",
- *     "uuid" = "uuid"
+ *     "uuid" = "uuid",
+ *     "owner" = "owner",
  *   },
  *   links = {
  *     "canonical" = "/private-message/{private_message}",
@@ -39,78 +41,42 @@ use Drupal\user\UserInterface;
  */
 class PrivateMessage extends ContentEntityBase implements PrivateMessageInterface {
 
-  /**
-   * {@inheritdoc}
-   *
-   * When a new private message is created, set the owner entity reference to
-   * the current user as the creator of the instance.
-   */
-  public static function preCreate(EntityStorageInterface $storage_controller, array &$values) {
-    parent::preCreate($storage_controller, $values);
-    $values += [
-      'owner' => \Drupal::currentUser()->id(),
-    ];
-  }
+  use EntityOwnerTrait;
 
   /**
    * {@inheritdoc}
    */
-  public function getCreatedTime() {
-    return $this->get('created')->value;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getOwner() {
-    return $this->get('owner')->entity;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getOwnerId() {
-    return $this->get('owner')->target_id;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setOwnerId($uid) {
-    $this->set('owner', $uid);
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setOwner(UserInterface $account) {
-    $this->set('owner', $account->id());
-    return $this;
+  public function getCreatedTime(): int {
+    return (int) $this->get('created')->value;
   }
 
   /**
    * {@inheritdoc}
+   *
+   * @deprecated in private_message:4.0.0 and is removed from
+   *   private_message:5.0.0. Instead, access the 'message' field.
+   *
+   * @see https://www.drupal.org/project/private_message/issues/3490037
    */
   public function getMessage() {
+    @trigger_error(__METHOD__ . "() is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. Instead, access the 'message' field. See https://www.drupal.org/project/private_message/issues/3490037", E_USER_DEPRECATED);
     return $this->get('message')->value;
   }
 
   /**
    * {@inheritdoc}
    */
-  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
+  public static function baseFieldDefinitions(EntityTypeInterface $entity_type): array {
     $fields = parent::baseFieldDefinitions($entity_type);
+    $fields += static::ownerBaseFieldDefinitions($entity_type);
+
     $fields['id']->setLabel(t('Private message ID'))
       ->setDescription(t('The private message ID.'));
 
     $fields['uuid']->setDescription(t('The custom private message UUID.'));
 
-    // Owner of the private message.
-    // Entity reference field, holds the reference to the user object. The view
-    // shows the user name field of the user. No form field is provided, as the
-    // user will always be the current user.
-    $fields['owner'] = BaseFieldDefinition::create('entity_reference')
+    // No form field is provided, as the user will always be the current user.
+    $fields['owner']
       ->setLabel(t('From'))
       ->setDescription(t('The author of the private message'))
       ->setSetting('target_type', 'user')
diff --git a/src/Entity/PrivateMessageInterface.php b/src/Entity/PrivateMessageInterface.php
index 22fa1ea1..3ec7e25d 100644
--- a/src/Entity/PrivateMessageInterface.php
+++ b/src/Entity/PrivateMessageInterface.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Entity;
 
 use Drupal\Core\Entity\ContentEntityInterface;
@@ -7,18 +9,16 @@ use Drupal\user\EntityOwnerInterface;
 
 /**
  * Provides an interface defining a Private Message entity.
- *
- * @ingroup private_message
  */
 interface PrivateMessageInterface extends ContentEntityInterface, EntityOwnerInterface {
 
   /**
-   * Get the time at which the private message was created.
+   * Gets the time at which the private message was created.
    *
    * @return int
    *   A Unix timestamp indicating the time at which the private message was
    *   created.
    */
-  public function getCreatedTime();
+  public function getCreatedTime(): int;
 
 }
-- 
GitLab


From 39a1096e91dd9822b1185ac9e3996f2d7ae1e22b Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Wed, 27 Nov 2024 21:42:27 +0200
Subject: [PATCH 10/30] Update private_message_ban entity type

---
 src/Entity/PrivateMessageBan.php          | 79 +++++++----------------
 src/Entity/PrivateMessageBanInterface.php | 14 ++--
 2 files changed, 29 insertions(+), 64 deletions(-)

diff --git a/src/Entity/PrivateMessageBan.php b/src/Entity/PrivateMessageBan.php
index 2dd09e1c..e4da0afb 100644
--- a/src/Entity/PrivateMessageBan.php
+++ b/src/Entity/PrivateMessageBan.php
@@ -1,14 +1,14 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Entity;
 
 use Drupal\Core\Entity\ContentEntityBase;
-use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
-use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
-use Drupal\user\Entity\User;
+use Drupal\user\EntityOwnerTrait;
 use Drupal\user\UserInterface;
 
 /**
@@ -16,8 +16,6 @@ use Drupal\user\UserInterface;
  *
  * This is a lightweight entity type used to store banned users.
  *
- * @ingroup private_message
- *
  * @ContentEntityType(
  *   id = "private_message_ban",
  *   label = @Translation("Private Message Ban"),
@@ -41,7 +39,7 @@ use Drupal\user\UserInterface;
  *   entity_keys = {
  *     "id" = "id",
  *     "uuid" = "uuid",
- *     "uid" = "owner",
+ *     "owner" = "owner",
  *   },
  *   links = {
  *     "add-form" = "/admin/structure/private_message_ban/add",
@@ -51,32 +49,24 @@ use Drupal\user\UserInterface;
  *   },
  *   constraints = {
  *     "UniquePrivateMessageBan" = {}
- *   }
+ *   },
  * )
  */
 class PrivateMessageBan extends ContentEntityBase implements PrivateMessageBanInterface {
 
-  /**
-   * {@inheritdoc}
-   */
-  public static function preCreate(EntityStorageInterface $storage_controller, array &$values) {
-    parent::preCreate($storage_controller, $values);
-    $values += [
-      'owner' => \Drupal::currentUser()->id(),
-    ];
-  }
+  use EntityOwnerTrait;
 
   /**
    * {@inheritdoc}
    */
   public function getCreatedTime(): int {
-    return $this->get('created')->value;
+    return (int) $this->get('created')->value;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function setCreatedTime($timestamp) {
+  public function setCreatedTime(int $timestamp): PrivateMessageBanInterface {
     $this->set('created', $timestamp);
     return $this;
   }
@@ -84,61 +74,34 @@ class PrivateMessageBan extends ContentEntityBase implements PrivateMessageBanIn
   /**
    * {@inheritdoc}
    */
-  public function getOwner() {
-    return $this->get('owner')->entity;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getOwnerId() {
-    return $this->get('owner')->target_id;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setOwnerId($uid) {
-    $this->set('owner', $uid);
-    return $this;
+  public function getTarget(): UserInterface {
+    $targetUser = $this->get('target')->entity;
+    assert($targetUser instanceof UserInterface);
+    return $targetUser;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function setOwner(UserInterface $account) {
-    $this->set('owner', $account->id());
-    return $this;
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  public function getTarget(): User {
-    return $this->get('target')->entity;
-  }
-
-  /**
-   * {@inheritDoc}
-   */
   public function getTargetId(): int {
-    return $this->get('target')->target_id;
+    return (int) $this->get('target')->target_id;
   }
 
   /**
-   * {@inheritDoc}
+   * {@inheritdoc}
    */
-  public function setTarget(AccountInterface $user): PrivateMessageBanInterface {
+  public function setTarget(UserInterface $user): PrivateMessageBanInterface {
     return $this->set('target', $user->id());
   }
 
   /**
    * {@inheritdoc}
    */
-  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
+  public static function baseFieldDefinitions(EntityTypeInterface $entity_type): array {
     $fields = parent::baseFieldDefinitions($entity_type);
+    $fields += static::ownerBaseFieldDefinitions($entity_type);
 
-    $fields['owner'] = BaseFieldDefinition::create('entity_reference')
+    $fields['owner']
       ->setLabel(t('Owned by'))
       ->setDescription(t('The ID of user who performed the ban.'))
       ->setSetting('target_type', 'user')
@@ -182,8 +145,10 @@ class PrivateMessageBan extends ContentEntityBase implements PrivateMessageBanIn
   /**
    * {@inheritdoc}
    */
-  public function label() {
-    return new TranslatableMarkup('Private Message Ban by @username', ['@username' => $this->getOwner()->getDisplayName()]);
+  public function label(): TranslatableMarkup {
+    return new TranslatableMarkup('Private Message Ban by @username', [
+      '@username' => $this->getOwner()->getDisplayName(),
+    ]);
   }
 
 }
diff --git a/src/Entity/PrivateMessageBanInterface.php b/src/Entity/PrivateMessageBanInterface.php
index 5c1fcbfd..7071220f 100644
--- a/src/Entity/PrivateMessageBanInterface.php
+++ b/src/Entity/PrivateMessageBanInterface.php
@@ -1,11 +1,12 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Entity;
 
 use Drupal\Core\Entity\ContentEntityInterface;
-use Drupal\Core\Session\AccountInterface;
-use Drupal\user\Entity\User;
 use Drupal\user\EntityOwnerInterface;
+use Drupal\user\UserInterface;
 
 /**
  * The Private Message Ban entity interface.
@@ -28,15 +29,14 @@ interface PrivateMessageBanInterface extends ContentEntityInterface, EntityOwner
    * @param int $timestamp
    *   The Private Message Ban creation timestamp.
    *
-   * @return \Drupal\private_message\Entity\PrivateMessageBanInterface
-   *   The called Private Message Ban entity.
+   * @return $this
    */
-  public function setCreatedTime($timestamp);
+  public function setCreatedTime(int $timestamp): self;
 
   /**
    * Gets banned user.
    */
-  public function getTarget(): User;
+  public function getTarget(): UserInterface;
 
   /**
    * Gets target id.
@@ -46,6 +46,6 @@ interface PrivateMessageBanInterface extends ContentEntityInterface, EntityOwner
   /**
    * Sets banned user.
    */
-  public function setTarget(AccountInterface $user): self;
+  public function setTarget(UserInterface $user): self;
 
 }
-- 
GitLab


From a6885c4eb82292ff12ef1e0972681212bb0fbc17 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Thu, 28 Nov 2024 20:48:02 +0200
Subject: [PATCH 11/30] Update private_message_thread entity type

---
 src/Entity/PrivateMessageThread.php          |  82 ++++++-----
 src/Entity/PrivateMessageThreadInterface.php | 137 +++++++++++--------
 src/Form/PrivateMessageForm.php              |   4 +-
 3 files changed, 127 insertions(+), 96 deletions(-)

diff --git a/src/Entity/PrivateMessageThread.php b/src/Entity/PrivateMessageThread.php
index 943a12d3..520bddcb 100644
--- a/src/Entity/PrivateMessageThread.php
+++ b/src/Entity/PrivateMessageThread.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Entity;
 
 use Drupal\Core\Cache\Cache;
@@ -44,39 +46,37 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
   /**
    * {@inheritdoc}
    */
-  public function addMember(AccountInterface $account) {
+  public function addMember(AccountInterface $account): PrivateMessageThreadInterface {
     if (!$this->isMember($account->id())) {
       $this->get('members')->appendItem($account->id());
     }
-
     return $this;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function addMemberById($id) {
+  public function addMemberById(int|string $id): PrivateMessageThreadInterface {
     if (!$this->isMember($id)) {
       $this->get('members')->appendItem($id);
     }
-
     return $this;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getMembers() {
+  public function getMembers(): array {
     return $this->get('members')->referencedEntities();
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getMembersId() {
+  public function getMemberIds(): array {
     $members = [];
     foreach ($this->get('members')->getValue() as $member_item) {
-      $members[] = $member_item['target_id'];
+      $members[] = (int) $member_item['target_id'];
     }
     return $members;
   }
@@ -84,14 +84,22 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
   /**
    * {@inheritdoc}
    */
-  public function isMember($id) {
-    return in_array($id, $this->getMembersId());
+  public function getMembersId(): array {
+    @trigger_error(__METHOD__ . '() is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. Use self::getMemberIds() instead. See https://www.drupal.org/node/3490530', E_USER_DEPRECATED);
+    return $this->getMemberIds();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isMember(int|string $id): bool {
+    return in_array((int) $id, $this->getMemberIds(), TRUE);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function addMessage(PrivateMessageInterface $privateMessage) {
+  public function addMessage(PrivateMessageInterface $privateMessage): PrivateMessageThreadInterface {
     $this->get('private_messages')->appendItem($privateMessage->id());
     // Allow other modules to react on a new message in thread.
     // @todo Inject when entity dependency serialization core issues resolved.
@@ -105,18 +113,17 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
   /**
    * {@inheritdoc}
    */
-  public function addMessageById($id) {
+  public function addMessageById(int|string $id): PrivateMessageThreadInterface {
     $this->get('private_messages')->appendItem($id);
-
     return $this;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getMessages(bool $include_banned = FALSE) {
+  public function getMessages(bool $includeBlocked = FALSE): array {
     $messages = $this->get('private_messages')->referencedEntities();
-    if ($include_banned) {
+    if ($includeBlocked) {
       return $messages;
     }
 
@@ -132,6 +139,8 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
    * {@inheritdoc}
    */
   public function filterNewestMessages() {
+    @trigger_error(__METHOD__ . "() is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. No replacement is provided. See https://www.drupal.org/node/3490530", E_USER_DEPRECATED);
+
     $messages = $this->getMessages();
     if (count($messages) > \Drupal::config('private_message_thread.settings')->get('message_count')) {
       $list = $this->get('private_messages');
@@ -152,11 +161,11 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
   /**
    * {@inheritdoc}
    */
-  public function getNewestMessageCreationTimestamp() {
+  public function getNewestMessageCreationTimestamp(): int {
     $messages = $this->getMessages();
     $last_timestamp = 0;
     foreach ($messages as $message) {
-      $creation_date = $message->get('created')->value;
+      $creation_date = (int) $message->get('created')->value;
       $last_timestamp = max($creation_date, $last_timestamp);
     }
 
@@ -166,7 +175,7 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
   /**
    * {@inheritdoc}
    */
-  public function addHistoryRecord(AccountInterface $account) {
+  public function addHistoryRecord(AccountInterface $account): void {
     \Drupal::database()->insert('pm_thread_history')
       ->fields([
         'uid' => $account->id(),
@@ -177,8 +186,8 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
   /**
    * {@inheritdoc}
    */
-  public function getLastAccessTimestamp(AccountInterface $account) {
-    return \Drupal::database()->select('pm_thread_history', 'pm_thread_history')
+  public function getLastAccessTimestamp(AccountInterface $account): int {
+    return (int) \Drupal::database()->select('pm_thread_history', 'pm_thread_history')
       ->condition('uid', $account->id())
       ->condition('thread_id', $this->id())
       ->fields('pm_thread_history', ['access_timestamp'])
@@ -189,7 +198,7 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
   /**
    * {@inheritdoc}
    */
-  public function updateLastAccessTime(AccountInterface $account) {
+  public function updateLastAccessTime(AccountInterface $account): PrivateMessageThreadInterface {
     \Drupal::database()->update('pm_thread_history')
       ->condition('uid', $account->id())
       ->condition('thread_id', $this->id())
@@ -201,8 +210,8 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
   /**
    * {@inheritdoc}
    */
-  public function getLastDeleteTimestamp(AccountInterface $account) {
-    return \Drupal::database()->select('pm_thread_history', 'pm_thread_history')
+  public function getLastDeleteTimestamp(AccountInterface $account): int {
+    return (int) \Drupal::database()->select('pm_thread_history', 'pm_thread_history')
       ->condition('uid', $account->id())
       ->condition('thread_id', $this->id())
       ->fields('pm_thread_history', ['delete_timestamp'])
@@ -213,7 +222,7 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
   /**
    * {@inheritdoc}
    */
-  public function updateLastDeleteTime(AccountInterface $account) {
+  public function updateLastDeleteTime(AccountInterface $account): PrivateMessageThreadInterface {
     \Drupal::database()->update('pm_thread_history')
       ->condition('uid', $account->id())
       ->condition('thread_id', $this->id())
@@ -226,6 +235,7 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
    * {@inheritdoc}
    */
   public function save() {
+    // @todo This should be investigated.
     $this->clearCacheTags();
     return parent::save();
   }
@@ -233,11 +243,12 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
   /**
    * {@inheritdoc}
    */
-  public static function preDelete(EntityStorageInterface $storage, array $entities) {
+  public static function preDelete(EntityStorageInterface $storage, array $entities): void {
     parent::preDelete($storage, $entities);
 
     // Delete the thread from the database, as well as all reference entities.
     foreach ($entities as $entity) {
+      assert($entity instanceof PrivateMessageThreadInterface);
       $messages = $entity->getMessages(TRUE);
       foreach ($messages as $message) {
         $message->delete();
@@ -251,9 +262,10 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
   /**
    * {@inheritdoc}
    */
-  public static function postDelete(EntityStorageInterface $storage, array $entities) {
+  public static function postDelete(EntityStorageInterface $storage, array $entities): void {
     parent::postDelete($storage, $entities);
     foreach ($entities as $entity) {
+      assert($entity instanceof PrivateMessageThreadInterface);
       $entity->clearCacheTags();
     }
   }
@@ -261,7 +273,7 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
   /**
    * {@inheritdoc}
    */
-  public function clearAccountHistory(?AccountInterface $account = NULL) {
+  public function clearAccountHistory(?AccountInterface $account = NULL): void {
     if (!$account) {
       $account = \Drupal::currentUser();
     }
@@ -287,7 +299,7 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
   /**
    * {@inheritdoc}
    */
-  public function filterUserDeletedMessages(AccountInterface $account) {
+  public function filterUserDeletedMessages(AccountInterface $account): array {
     $last_delete_timestamp = $this->getLastDeleteTimestamp($account);
     $messages = $this->getMessages();
     $start_index = FALSE;
@@ -308,15 +320,17 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
 
   /**
    * {@inheritdoc}
+   *
+   * @todo Add to interface?
    */
-  public function getUpdatedTime() {
-    return $this->get('updated')->value;
+  public function getUpdatedTime(): int {
+    return (int) $this->get('updated')->value;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function clearCacheTags() {
+  public function clearCacheTags(): void {
     $tags = [];
 
     foreach ($this->getMembers() as $member) {
@@ -334,8 +348,8 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
   /**
    * {@inheritdoc}
    */
-  public static function baseFieldDefinitions(EntityTypeInterface $entityType) {
-    $fields = parent::baseFieldDefinitions($entityType);
+  public static function baseFieldDefinitions(EntityTypeInterface $entity_type): array {
+    $fields = parent::baseFieldDefinitions($entity_type);
 
     $fields['id']->setLabel(t('Private message thread ID'))
       ->setDescription(t('The private message thread ID.'));
@@ -406,7 +420,7 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
   /**
    * {@inheritdoc}
    */
-  public function getCacheTags() {
+  public function getCacheTags(): array {
     $tags = parent::getCacheTags();
     $tags[] = 'private_message_thread:' . $this->id() . ':view:uid:' . \Drupal::currentUser()->id();
 
@@ -416,7 +430,7 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
   /**
    * {@inheritdoc}
    */
-  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
+  public function postSave(EntityStorageInterface $storage, $update = TRUE): void {
     parent::postSave($storage, $update);
     if (!$update) {
       $members = $this->getMembers();
diff --git a/src/Entity/PrivateMessageThreadInterface.php b/src/Entity/PrivateMessageThreadInterface.php
index f58ae2e5..598f4e8d 100644
--- a/src/Entity/PrivateMessageThreadInterface.php
+++ b/src/Entity/PrivateMessageThreadInterface.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Entity;
 
 use Drupal\Core\Entity\ContentEntityInterface;
@@ -7,112 +9,130 @@ use Drupal\Core\Session\AccountInterface;
 
 /**
  * Provides an interface defining a Private Message thread entity.
- *
- * @ingroup private_message
  */
 interface PrivateMessageThreadInterface extends ContentEntityInterface {
 
   /**
-   * Add a member to the private message thread.
+   * Adds a member to the private message thread.
    *
    * @param \Drupal\Core\Session\AccountInterface $account
    *   The account to be set as a member of the private message thread.
    *
-   * @return \Drupal\private_message\Entity\PrivateMessageInterface
-   *   Returns the class itself to allow for chaining.
+   * @return $this
    */
-  public function addMember(AccountInterface $account);
+  public function addMember(AccountInterface $account): self;
 
   /**
-   * Add a member to the private message thread.
+   * Adds a member to the private message thread by its ID.
+   *
+   * @param int|string $id
+   *   The ID of the user to be set as a member of the private message thread.
    *
-   * @param int $id
-   *   The ID of the account to be set as a member of the private message
-   *   thread.
+   * @return $this
+   */
+  public function addMemberById(int|string $id): self;
+
+  /**
+   * Retrieves the IDs of the members of the private message thread.
    *
-   * @return \Drupal\private_message\Entity\PrivateMessageInterface
-   *   Returns the class itself to allow for chaining.
+   * @return int[]
+   *   A list of member IDs
    */
-  public function addMemberById($id);
+  public function getMemberIds(): array;
 
   /**
-   * Retrieve the ids of the members of the private message thread.
+   * Retrieves the IDs of the members of the private message thread.
+   *
+   * @return int[]
+   *   A list of member IDs
+   *
+   * @deprecated in private_message:4.0.0 and is removed from
+   *   private_message:5.0.0. Use self::getMemberIds() instead.
+   *
+   * @see https://www.drupal.org/node/3490530
    */
-  public function getMembersId();
+  public function getMembersId(): array;
 
   /**
-   * Retrieve the members of the private message thread.
+   * Retrieves the members of the private message thread.
+   *
+   * @return \Drupal\user\UserInterface[]
+   *   A list of members user accounts.
    */
-  public function getMembers();
+  public function getMembers(): array;
 
   /**
-   * Check if the user with the given ID is a member of the thread.
+   * Checks if the user with the given ID is a member of the thread.
    *
-   * @param int $id
+   * @param int|string $id
    *   The User ID of the user to check.
    *
    * @return bool
-   *   - TRUE if the user is a member of the thread
-   *   - FALSE if they are not
+   *   Whether the user is member of the thread.
    */
-  public function isMember($id);
+  public function isMember(int|string $id): bool;
 
   /**
-   * Add a private message to the list of messages in this thread.
+   * Adds a private message to the list of messages in this thread.
    *
    * @param \Drupal\private_message\Entity\PrivateMessageInterface $privateMessage
    *   The private message to be added to the thread.
    *
-   * @return \Drupal\private_message\Entity\PrivateMessageThread
-   *   The private message thread.
+   * @return $this
    */
-  public function addMessage(PrivateMessageInterface $privateMessage);
+  public function addMessage(PrivateMessageInterface $privateMessage): self;
 
   /**
-   * Add a private message by ID to the list of the messages in this thread.
+   * Adds a private message by ID to the list of the messages in this thread.
    *
-   * @param int $id
+   * @param int|string $id
    *   The ID of the private message to be added to the thread.
+   *
+   * @return $this
    */
-  public function addMessageById($id);
+  public function addMessageById(int|string $id): self;
 
   /**
-   * Retrieve all private messages attached to this thread.
+   * Retrieves all private messages attached to this thread.
    *
-   * @param bool $include_banned
-   *   (Optional) Whether to include messages from banned users. Defaults to
-   *   FALSE.
+   * @param bool $includeBlocked
+   *   (optional) Include messages from blocked users? Defaults to FALSE.
    *
-   * @return \Drupal\Core\Field\EntityReferenceFieldItemListInterface
+   * @return \Drupal\private_message\Entity\PrivateMessageInterface[]
    *   A list of private messages attached to this thread
    */
-  public function getMessages(bool $include_banned = FALSE);
+  public function getMessages(bool $includeBlocked = FALSE): array;
 
   /**
-   * Filter the list down to only the newest messages.
+   * Filters the list down to only the newest messages.
    *
    * Note that other messages will be loadable through AJAX.
+   *
+   * @deprecated in private_message:4.0.0 and is removed from
+   *   private_message:5.0.0. No replacement is provided.
+   *
+   * @see https://www.drupal.org/node/3490530
    */
   public function filterNewestMessages();
 
   /**
-   * Get the created timestamp of the newest private message in the thread.
+   * Gets the created timestamp of the newest private message in the thread.
    *
    * @return int
    *   The Unix timestamp of the newest message in the thread
    */
-  public function getNewestMessageCreationTimestamp();
+  public function getNewestMessageCreationTimestamp(): int;
 
   /**
-   * Add a history record to the current thread for the given user.
+   * Adds a history record to the current thread for the given user.
    *
    * @param \Drupal\Core\Session\AccountInterface $account
    *   The user whose access time should be updated.
    */
-  public function addHistoryRecord(AccountInterface $account);
+  public function addHistoryRecord(AccountInterface $account): void;
 
   /**
-   * Get the last access timestamp for the given user.
+   * Gets the last access timestamp for the given user.
    *
    * @param \Drupal\Core\Session\AccountInterface $account
    *   The user whose last access time should be retrieved.
@@ -120,18 +140,20 @@ interface PrivateMessageThreadInterface extends ContentEntityInterface {
    * @return int
    *   The timestamp at which the user last accessed the thread
    */
-  public function getLastAccessTimestamp(AccountInterface $account);
+  public function getLastAccessTimestamp(AccountInterface $account): int;
 
   /**
-   * Update the last access time for the given user.
+   * Updates the last access time for the given user.
    *
    * @param \Drupal\Core\Session\AccountInterface $account
    *   The user whose last access time should be updated.
+   *
+   * @return $this
    */
-  public function updateLastAccessTime(AccountInterface $account);
+  public function updateLastAccessTime(AccountInterface $account): self;
 
   /**
-   * Get the last delete timestamp for the given user.
+   * Gets the last delete timestamp for the given user.
    *
    * @param \Drupal\Core\Session\AccountInterface $account
    *   The user whose last delete time should be retrieved.
@@ -140,22 +162,17 @@ interface PrivateMessageThreadInterface extends ContentEntityInterface {
    *   A UNIX timestamp indicating the last time the user marked the thread as
    *   deleted.
    */
-  public function getLastDeleteTimestamp(AccountInterface $account);
+  public function getLastDeleteTimestamp(AccountInterface $account): int;
 
   /**
-   * Update the last delete time for the given user.
+   * Updates the last delete time for the given user.
    *
    * @param \Drupal\Core\Session\AccountInterface $account
    *   The user whose last delete time should be updated.
-   */
-  public function updateLastDeleteTime(AccountInterface $account);
-
-  /**
-   * Performs a complete delete action on the private message thread.
    *
-   * Includes deleting of all messages.
+   * @return $this
    */
-  public function delete();
+  public function updateLastDeleteTime(AccountInterface $account): self;
 
   /**
    * Provides clear thread history feature.
@@ -173,10 +190,10 @@ interface PrivateMessageThreadInterface extends ContentEntityInterface {
    *   (Optional) Account for which thread history will be cleared.
    *   If no account provided, the current user will be used.
    */
-  public function clearAccountHistory(?AccountInterface $account = NULL);
+  public function clearAccountHistory(?AccountInterface $account = NULL): void;
 
   /**
-   * Filter messages in the thread deleted by the given account.
+   * Filters messages in the thread deleted by the given account.
    *
    * Only messages created after the last time the user deleted the thread will
    * be shown. If they have never deleted the thread, all messages are returned.
@@ -184,14 +201,14 @@ interface PrivateMessageThreadInterface extends ContentEntityInterface {
    * @param \Drupal\Core\Session\AccountInterface $account
    *   The user for whom private messages should be returned.
    *
-   * @return Drupal\private_message\Entity\PrivateMessage[]
+   * @return \Drupal\private_message\Entity\PrivateMessageInterface[]
    *   An array of private messages
    */
-  public function filterUserDeletedMessages(AccountInterface $account);
+  public function filterUserDeletedMessages(AccountInterface $account): array;
 
   /**
-   * Clear cache tags related to private message thread entities.
+   * Clears cache tags related to private message thread entities.
    */
-  public function clearCacheTags();
+  public function clearCacheTags(): void;
 
 }
diff --git a/src/Form/PrivateMessageForm.php b/src/Form/PrivateMessageForm.php
index 26588c08..6b08d570 100644
--- a/src/Form/PrivateMessageForm.php
+++ b/src/Form/PrivateMessageForm.php
@@ -93,7 +93,7 @@ class PrivateMessageForm extends ContentEntityForm {
 
     if ($privateMessageThread) {
 
-      $threadMembers = $privateMessageThread->getMembersId();
+      $threadMembers = $privateMessageThread->getMemberIds();
       $bannedUsers = $this->privateMessageBanManager->getBannedUsers($this->currentUser()->id());
 
       $banned = FALSE;
@@ -276,7 +276,7 @@ class PrivateMessageForm extends ContentEntityForm {
 
     /** @var \Drupal\private_message\Entity\PrivateMessageThread|null $privateMessageThread */
     $privateMessageThread = $formState->get('thread');
-    $threadMembers = $privateMessageThread ? $privateMessageThread->getMembersId() : [];
+    $threadMembers = $privateMessageThread ? $privateMessageThread->getMemberIds() : [];
     $bannedUsers = $this->privateMessageBanManager->getBannedUsers($this->currentUser()->id());
 
     foreach ($bannedUsers as $bannedUser) {
-- 
GitLab


From 5fbef290a2179785897b6257dc3ef6bae7262b18 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Thu, 28 Nov 2024 20:48:44 +0200
Subject: [PATCH 12/30] Change deprecation docs

---
 src/Entity/PrivateMessage.php | 4 ++--
 src/Form/ConfigForm.php       | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/Entity/PrivateMessage.php b/src/Entity/PrivateMessage.php
index 7ccebcef..1ccb2e68 100644
--- a/src/Entity/PrivateMessage.php
+++ b/src/Entity/PrivateMessage.php
@@ -56,10 +56,10 @@ class PrivateMessage extends ContentEntityBase implements PrivateMessageInterfac
    * @deprecated in private_message:4.0.0 and is removed from
    *   private_message:5.0.0. Instead, access the 'message' field.
    *
-   * @see https://www.drupal.org/project/private_message/issues/3490037
+   * @see https://www.drupal.org/node/3490530
    */
   public function getMessage() {
-    @trigger_error(__METHOD__ . "() is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. Instead, access the 'message' field. See https://www.drupal.org/project/private_message/issues/3490037", E_USER_DEPRECATED);
+    @trigger_error(__METHOD__ . "() is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. Instead, access the 'message' field. See https://www.drupal.org/node/3490530", E_USER_DEPRECATED);
     return $this->get('message')->value;
   }
 
diff --git a/src/Form/ConfigForm.php b/src/Form/ConfigForm.php
index 54178e80..79dcc4dd 100644
--- a/src/Form/ConfigForm.php
+++ b/src/Form/ConfigForm.php
@@ -24,7 +24,7 @@ class ConfigForm extends ConfigFormBase {
    * private_message:5.0.0. Use \Drupal\private_message\Model\BlockType::Passive
    * instead.
    *
-   * @see https://www.drupal.org/project/private_message/issues/3490037
+   * @see https://www.drupal.org/node/3490530
    */
   const PASSIVE = 'passive';
 
@@ -35,7 +35,7 @@ class ConfigForm extends ConfigFormBase {
    * private_message:5.0.0. Use \Drupal\private_message\Model\BlockType::Active
    * instead.
    *
-   * @see https://www.drupal.org/project/private_message/issues/3490037
+   * @see https://www.drupal.org/node/3490530
    */
   const ACTIVE = 'active';
 
-- 
GitLab


From 0a388e118fb20237971220c3c1f1e57e43d24199 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Thu, 28 Nov 2024 20:49:23 +0200
Subject: [PATCH 13/30] Strict type PrivateMessageBanManagerInterface

---
 src/Service/PrivateMessageBanManager.php      | 20 ++++++++++------
 .../PrivateMessageBanManagerInterface.php     | 23 ++++++++++++-------
 2 files changed, 28 insertions(+), 15 deletions(-)

diff --git a/src/Service/PrivateMessageBanManager.php b/src/Service/PrivateMessageBanManager.php
index 4a9503f5..8fefd944 100644
--- a/src/Service/PrivateMessageBanManager.php
+++ b/src/Service/PrivateMessageBanManager.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Service;
 
 use Drupal\Core\Database\Connection;
@@ -24,7 +26,7 @@ class PrivateMessageBanManager implements PrivateMessageBanManagerInterface {
   /**
    * {@inheritdoc}
    */
-  public function isBanned(int $user_id): bool {
+  public function isBanned(int|string $user_id): bool {
     $select = $this
       ->database
       ->select('private_message_ban', 'pmb');
@@ -41,6 +43,8 @@ class PrivateMessageBanManager implements PrivateMessageBanManagerInterface {
    * {@inheritdoc}
    */
   public function isCurrentUserBannedByUser(int $user_id): bool {
+    @trigger_error(__METHOD__ . '() is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. No replacement is provided. See https://www.drupal.org/node/3490530', E_USER_DEPRECATED);
+
     $select = $this
       ->database
       ->select('private_message_ban', 'pmb');
@@ -56,7 +60,7 @@ class PrivateMessageBanManager implements PrivateMessageBanManagerInterface {
   /**
    * {@inheritdoc}
    */
-  public function getBannedUsers(int $user_id): array {
+  public function getBannedUsers(int|string $user_id): array {
     return $this
       ->database
       ->select('private_message_ban', 'pmb')
@@ -69,8 +73,8 @@ class PrivateMessageBanManager implements PrivateMessageBanManagerInterface {
   /**
    * {@inheritdoc}
    */
-  public function unbanUser(int $user_id) {
-    $ban = $this->findBanEntity($this->currentUser->id(), $user_id);
+  public function unbanUser(int|string $user_id): void {
+    $ban = $this->findBanEntity((int) $this->currentUser->id(), (int) $user_id);
     if (!$ban) {
       // The user is not banned; just return.
       return;
@@ -83,8 +87,8 @@ class PrivateMessageBanManager implements PrivateMessageBanManagerInterface {
   /**
    * {@inheritdoc}
    */
-  public function banUser(int $user_id) {
-    $ban = $this->findBanEntity($this->currentUser->id(), $user_id);
+  public function banUser(int|string $user_id): void {
+    $ban = $this->findBanEntity((int) $this->currentUser->id(), (int) $user_id);
     if ($ban) {
       // The user is already banned; just return.
       return;
@@ -122,7 +126,9 @@ class PrivateMessageBanManager implements PrivateMessageBanManagerInterface {
 
     // reset() returns the first element of the array or FALSE if the array is
     // empty, but we want the return value to be NULL if the array is empty.
-    return reset($bans) ?: NULL;
+    $ban = reset($bans) ?: NULL;
+    assert($ban === NULL || $ban instanceof PrivateMessageBanInterface);
+    return $ban;
   }
 
 }
diff --git a/src/Service/PrivateMessageBanManagerInterface.php b/src/Service/PrivateMessageBanManagerInterface.php
index 8d230708..92d5ad86 100644
--- a/src/Service/PrivateMessageBanManagerInterface.php
+++ b/src/Service/PrivateMessageBanManagerInterface.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Service;
 
 /**
@@ -10,13 +12,13 @@ interface PrivateMessageBanManagerInterface {
   /**
    * Check if the user is banned by the current user.
    *
-   * @param int $user_id
+   * @param int|string $user_id
    *   ID of the target user to test.
    *
    * @return bool
    *   TRUE if the given user is banned by the current user. FALSE otherwise.
    */
-  public function isBanned(int $user_id): bool;
+  public function isBanned(int|string $user_id): bool;
 
   /**
    * Checks if the current user is banned by the user.
@@ -26,34 +28,39 @@ interface PrivateMessageBanManagerInterface {
    *
    * @return bool
    *   TRUE if the current user is banned by the given user. FALSE otherwise.
+   *
+   * @deprecated in private_message:4.0.0 and is removed from
+   *   private_message:5.0.0. No replacement is provided.
+   *
+   * @see https://www.drupal.org/node/3490530
    */
   public function isCurrentUserBannedByUser(int $user_id): bool;
 
   /**
    * Returns list of users banned by a user with given ID.
    *
-   * @param int $user_id
+   * @param int|string $user_id
    *   ID of the user to test.
    *
    * @return array
    *   An array of user ids that the user has banned.
    */
-  public function getBannedUsers(int $user_id): array;
+  public function getBannedUsers(int|string $user_id): array;
 
   /**
    * Adds a user to the current user's banned users list.
    *
-   * @param int $user_id
+   * @param int|string $user_id
    *   ID of the user to ban.
    */
-  public function banUser(int $user_id);
+  public function banUser(int|string $user_id): void;
 
   /**
    * Removes a banned user from their banned users list.
    *
-   * @param int $user_id
+   * @param int|string $user_id
    *   ID of the user to unban.
    */
-  public function unbanUser(int $user_id);
+  public function unbanUser(int|string $user_id): void;
 
 }
-- 
GitLab


From b0ac05a734cdf128c9b8dd2372d55fd97d768ecf Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Thu, 28 Nov 2024 22:40:24 +0200
Subject: [PATCH 14/30] Deprecate private_message.mapper service

---
 private_message.services.yml                  |   1 +
 src/Mapper/PrivateMessageMapper.php           |   7 +
 src/Mapper/PrivateMessageMapperInterface.php  |   7 +
 .../PrivateMessageThreadHasNewMessage.php     |   8 +-
 .../PrivateMessageThreadNewMessagesCount.php  |   8 +-
 src/Service/PrivateMessageService.php         | 377 +++++++++++++++++-
 .../PrivateMessageServiceInterface.php        |  16 +
 7 files changed, 403 insertions(+), 21 deletions(-)

diff --git a/private_message.services.yml b/private_message.services.yml
index 825ceb4c..a5e9c19b 100644
--- a/private_message.services.yml
+++ b/private_message.services.yml
@@ -6,6 +6,7 @@ services:
 
   private_message.mapper:
     class: Drupal\private_message\Mapper\PrivateMessageMapper
+    deprecated: The "%service_id%" service is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. No replacement is provided. See https://www.drupal.org/node/3490530
   Drupal\private_message\Mapper\PrivateMessageMapperInterface: '@private_message.mapper'
 
   private_message.service:
diff --git a/src/Mapper/PrivateMessageMapper.php b/src/Mapper/PrivateMessageMapper.php
index 68ace052..24a086c2 100644
--- a/src/Mapper/PrivateMessageMapper.php
+++ b/src/Mapper/PrivateMessageMapper.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\private_message\Mapper;
 
+@trigger_error(__CLASS__ . ' is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. No replacement is provided. See https://www.drupal.org/node/3490530', E_USER_DEPRECATED);
+
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Session\AccountProxyInterface;
@@ -10,6 +12,11 @@ use Drupal\user\UserInterface;
 
 /**
  * Interface for the Private Message Mapper class.
+ *
+ * @deprecated in private_message:4.0.0 and is removed from
+ *   private_message:5.0.0. No replacement is provided.
+ *
+ * @see https://www.drupal.org/node/3490530
  */
 class PrivateMessageMapper implements PrivateMessageMapperInterface {
 
diff --git a/src/Mapper/PrivateMessageMapperInterface.php b/src/Mapper/PrivateMessageMapperInterface.php
index 63ddc1cf..45294330 100644
--- a/src/Mapper/PrivateMessageMapperInterface.php
+++ b/src/Mapper/PrivateMessageMapperInterface.php
@@ -2,11 +2,18 @@
 
 namespace Drupal\private_message\Mapper;
 
+@trigger_error(__CLASS__ . ' is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. No replacement is provided. See https://www.drupal.org/node/3490530', E_USER_DEPRECATED);
+
 use Drupal\private_message\Entity\PrivateMessageInterface;
 use Drupal\user\UserInterface;
 
 /**
  * Interface for the Private Message Thread mapper class.
+ *
+ * @deprecated in private_message:4.0.0 and is removed from
+ *   private_message:5.0.0. No replacement is provided.
+ *
+ * @see https://www.drupal.org/node/3490530
  */
 interface PrivateMessageMapperInterface {
 
diff --git a/src/Plugin/views/field/PrivateMessageThreadHasNewMessage.php b/src/Plugin/views/field/PrivateMessageThreadHasNewMessage.php
index b400917e..0366e16f 100644
--- a/src/Plugin/views/field/PrivateMessageThreadHasNewMessage.php
+++ b/src/Plugin/views/field/PrivateMessageThreadHasNewMessage.php
@@ -3,7 +3,7 @@
 namespace Drupal\private_message\Plugin\views\field;
 
 use Drupal\Core\Session\AccountInterface;
-use Drupal\private_message\Mapper\PrivateMessageMapperInterface;
+use Drupal\private_message\Service\PrivateMessageServiceInterface;
 use Drupal\views\Attribute\ViewsField;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\ResultRow;
@@ -22,7 +22,7 @@ class PrivateMessageThreadHasNewMessage extends FieldPluginBase {
     $plugin_id,
     $plugin_definition,
     protected readonly AccountInterface $currentUser,
-    protected readonly PrivateMessageMapperInterface $mapper,
+    protected readonly PrivateMessageServiceInterface $privateMessageService,
   ) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
   }
@@ -36,7 +36,7 @@ class PrivateMessageThreadHasNewMessage extends FieldPluginBase {
       $plugin_id,
       $plugin_definition,
       $container->get('current_user'),
-      $container->get('private_message.mapper')
+      $container->get('private_message.service')
     );
   }
 
@@ -54,7 +54,7 @@ class PrivateMessageThreadHasNewMessage extends FieldPluginBase {
     /** @var \Drupal\private_message\Entity\PrivateMessageThread $thread */
     $thread = $this->getEntity($values);
 
-    return $this->mapper->getThreadUnreadMessageCount($this->currentUser->id(), $thread->id()) > 0 ?
+    return $this->privateMessageService->getThreadUnreadMessageCount($this->currentUser->id(), $thread->id()) > 0 ?
       $this->t('New message!') :
       $this->t('No new messages');
   }
diff --git a/src/Plugin/views/field/PrivateMessageThreadNewMessagesCount.php b/src/Plugin/views/field/PrivateMessageThreadNewMessagesCount.php
index 79d47e64..83fd3360 100644
--- a/src/Plugin/views/field/PrivateMessageThreadNewMessagesCount.php
+++ b/src/Plugin/views/field/PrivateMessageThreadNewMessagesCount.php
@@ -3,7 +3,7 @@
 namespace Drupal\private_message\Plugin\views\field;
 
 use Drupal\Core\Session\AccountInterface;
-use Drupal\private_message\Mapper\PrivateMessageMapperInterface;
+use Drupal\private_message\Service\PrivateMessageServiceInterface;
 use Drupal\views\Attribute\ViewsField;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
 use Drupal\views\ResultRow;
@@ -22,7 +22,7 @@ class PrivateMessageThreadNewMessagesCount extends FieldPluginBase {
     $plugin_id,
     $plugin_definition,
     protected readonly AccountInterface $currentUser,
-    protected readonly PrivateMessageMapperInterface $mapper,
+    protected readonly PrivateMessageServiceInterface $privateMessageService,
   ) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
   }
@@ -36,7 +36,7 @@ class PrivateMessageThreadNewMessagesCount extends FieldPluginBase {
       $plugin_id,
       $plugin_definition,
       $container->get('current_user'),
-      $container->get('private_message.mapper')
+      $container->get('private_message.service')
     );
   }
 
@@ -55,7 +55,7 @@ class PrivateMessageThreadNewMessagesCount extends FieldPluginBase {
     $thread = $this->getEntity($values);
 
     // @todo Optimize this, consider deletions and banned users.
-    return $this->mapper->getThreadUnreadMessageCount($this->currentUser->id(), $thread->id());
+    return $this->privateMessageService->getThreadUnreadMessageCount($this->currentUser->id(), $thread->id());
   }
 
 }
diff --git a/src/Service/PrivateMessageService.php b/src/Service/PrivateMessageService.php
index 17c2d4f5..d2f0b25a 100644
--- a/src/Service/PrivateMessageService.php
+++ b/src/Service/PrivateMessageService.php
@@ -5,6 +5,8 @@ namespace Drupal\private_message\Service;
 use Drupal\Component\Datetime\TimeInterface;
 use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Database\Connection;
+use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
@@ -12,30 +14,33 @@ use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\Core\Url;
 use Drupal\private_message\Entity\PrivateMessageInterface;
 use Drupal\private_message\Entity\PrivateMessageThreadInterface;
-use Drupal\private_message\Mapper\PrivateMessageMapperInterface;
 use Drupal\user\UserDataInterface;
 use Drupal\user\UserInterface;
 
 /**
  * The Private Message service for the private message module.
+ *
+ * @todo Replace direct calls to database with entity API calls and remove the
+ *   $database class property in #3489224.
+ * @see https://www.drupal.org/project/private_message/issues/3489224
  */
 class PrivateMessageService implements PrivateMessageServiceInterface {
 
   public function __construct(
-    protected readonly PrivateMessageMapperInterface $mapper,
     protected readonly AccountProxyInterface $currentUser,
     protected readonly ConfigFactoryInterface $configFactory,
     protected readonly UserDataInterface $userData,
     protected readonly CacheTagsInvalidatorInterface $cacheTagsInvalidator,
     protected readonly EntityTypeManagerInterface $entityTypeManager,
     protected readonly TimeInterface $time,
+    protected readonly Connection $database,
   ) {}
 
   /**
    * {@inheritdoc}
    */
   public function getThreadForMembers(array $members) {
-    $thread_id = $this->mapper->getThreadIdForMembers($members);
+    $thread_id = $this->getThreadIdForMembers($members);
 
     if ($thread_id) {
       return $this->entityTypeManager
@@ -50,7 +55,7 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
    * {@inheritdoc}
    */
   public function getFirstThreadForUser(UserInterface $user) {
-    $thread_id = $this->mapper->getFirstThreadIdForUser($user);
+    $thread_id = $this->getFirstThreadIdForUser($user);
     if ($thread_id) {
       return $this->entityTypeManager
         ->getStorage('private_message_thread')
@@ -72,7 +77,7 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
     $user = $this->entityTypeManager
       ->getStorage('user')
       ->load($this->currentUser->id());
-    $thread_ids = $this->mapper->getThreadIdsForUser($user, $count, $timestamp);
+    $thread_ids = $this->getThreadIdsForUser($user, $count, $timestamp);
     if (count($thread_ids)) {
       $threads = $this->entityTypeManager
         ->getStorage('private_message_thread')
@@ -80,7 +85,7 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
       if (count($threads)) {
         $last_thread = end($threads);
         $last_timestamp = $last_thread->get('updated')->value;
-        $return['next_exists'] = $this->mapper->checkForNextThread($user, $last_timestamp);
+        $return['next_exists'] = $this->checkForNextThread($user, $last_timestamp);
         $return['threads'] = $threads;
       }
     }
@@ -95,7 +100,7 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
     $user = $this->entityTypeManager
       ->getStorage('user')
       ->load($this->currentUser->id());
-    $thread_ids = $this->mapper->getThreadIdsForUser($user);
+    $thread_ids = $this->getThreadIdsForUser($user);
     return count($thread_ids);
   }
 
@@ -180,7 +185,7 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
    * {@inheritdoc}
    */
   public function getUpdatedInboxThreads(array $existingThreadInfo, $count = FALSE) {
-    $thread_info = $this->mapper->getUpdatedInboxThreadIds(array_keys($existingThreadInfo), $count);
+    $thread_info = $this->getUpdatedInboxThreadIds(array_keys($existingThreadInfo), $count);
     $new_threads = [];
     $thread_ids = [];
     $ids_to_load = [];
@@ -211,7 +216,7 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
     $last_check_timestamp = $this->userData->get(self::MODULE_KEY, $uid, self::LAST_CHECK_KEY);
     $last_check_timestamp = is_numeric($last_check_timestamp) ? $last_check_timestamp : 0;
 
-    return (int) $this->mapper->getUnreadThreadCount($uid, $last_check_timestamp);
+    return (int) $this->getUnreadThreadCountHelper($uid, $last_check_timestamp);
   }
 
   /**
@@ -222,7 +227,7 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
     $last_check_timestamp = $this->userData->get(self::MODULE_KEY, $uid, self::LAST_CHECK_KEY);
     $last_check_timestamp = is_numeric($last_check_timestamp) ? $last_check_timestamp : 0;
 
-    return (int) $this->mapper->getUnreadMessageCount($uid, $last_check_timestamp);
+    return (int) $this->getUnreadMessageCountHelper($uid, $last_check_timestamp);
   }
 
   /**
@@ -249,7 +254,7 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
    * {@inheritdoc}
    */
   public function getThreadFromMessage(PrivateMessageInterface $privateMessage) {
-    $thread_id = $this->mapper->getThreadIdFromMessage($privateMessage);
+    $thread_id = $this->getThreadIdFromMessage($privateMessage);
     if ($thread_id) {
       return $this->entityTypeManager
         ->getStorage('private_message_thread')
@@ -274,7 +279,7 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
       if ($current_user->isAuthenticated()) {
         if ($current_user->hasPermission('use private messaging system') && $current_user->id() != $author->id()) {
           $members = [$current_user, $author];
-          $thread_id = $this->mapper->getThreadIdForMembers($members);
+          $thread_id = $this->getThreadIdForMembers($members);
           if ($thread_id) {
             $url = Url::fromRoute('entity.private_message_thread.canonical', ['private_message_thread' => $thread_id], ['attributes' => ['class' => ['private_message_link']]]);
             $build['private_message_link'] = [
@@ -314,7 +319,32 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
    * {@inheritdoc}
    */
   public function getThreadIds() {
-    return $this->mapper->getThreadIds();
+    return $this->database->select('private_message_threads', 'pmt')
+      ->fields('pmt', ['id'])
+      ->execute()
+      ->fetchCol();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getThreadUnreadMessageCount($uid, $thread_id) {
+    // @todo Optimize this, consider deletions and banned users.
+    $query = $this->database->select('pm_thread_history', 'pm_thread_history')
+      ->condition('uid', $uid)
+      ->condition('thread_id', $thread_id);
+    $query->join(
+      'private_message_thread__private_messages',
+      'thread_message',
+      'thread_message.entity_id = pm_thread_history.thread_id'
+    );
+    $query->join(
+      'private_messages',
+      'messages_data',
+      'messages_data.id = thread_message.private_messages_target_id'
+    );
+    $query->where('[messages_data].[created] > [pm_thread_history].[access_timestamp]');
+    return $query->countQuery()->execute()->fetchField();
   }
 
   /**
@@ -340,4 +370,325 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
     return $thread;
   }
 
+  /**
+   * Retrieves the ID of a thread from the database given a list of members.
+   *
+   * @param \Drupal\user\UserInterface[] $members
+   *   A list of users, members of a given thread.
+   *
+   * @return int|false
+   *   The thread ID, if a thread is found, or FALSE.
+   */
+  protected function getThreadIdForMembers(array $members): int|false {
+    $uids = array_map(fn(UserInterface $user) => (int) $user->id(), $members);
+
+    // Select threads common for the given members.
+    $query = $this->database->select('private_message_thread__members', 'pmt')
+      ->fields('pmt', ['entity_id'])
+      ->groupBy('entity_id');
+    // Add conditions where the threads are in the set of threads for each of
+    // the users.
+    foreach ($uids as $uid) {
+      $subQuery = $this->database->select('private_message_thread__members', 'pmt')
+        ->fields('pmt', ['entity_id'])
+        ->condition('members_target_id', $uid);
+      $query->condition('entity_id', $subQuery, 'IN');
+    }
+    $thread_ids = $query->execute()->fetchCol();
+
+    // Exclude threads with other participants.
+    foreach ($thread_ids as $thread_id) {
+      $query = $this->database->select('private_message_thread__members', 'pmt')
+        ->condition('members_target_id', $uids, 'NOT IN')
+        ->condition('entity_id', $thread_id);
+      if ($query->countQuery()->execute()->fetchField() == 0) {
+        return (int) $thread_id;
+      }
+    }
+
+    return FALSE;
+  }
+
+  /**
+   * Retrieves the ID of the most recently updated thread for the given user.
+   *
+   * @param \Drupal\user\UserInterface $user
+   *   The user whose most recently updated thread should be retrieved.
+   *
+   * @return int|false
+   *   The ID of the most recently updated thread where the user is a member, or
+   *   FALSE if one doesn't exist.
+   */
+  protected function getFirstThreadIdForUser(UserInterface $user): int|false {
+    $bannedThreadsQuery = $this->getBannedThreads($user->id());
+
+    $query = $this->database->select('private_message_threads', 'thread');
+    $query->addField('thread', 'id');
+    $query->innerJoin('pm_thread_history', 'thread_history', 'thread_history.thread_id = thread.id AND thread_history.uid = :uid', [':uid' => $user->id()]);
+    $query->innerJoin('private_message_thread__members', 'thread_member', 'thread_member.entity_id = thread.id AND thread_member.members_target_id = :uid', [':uid' => $user->id()]);
+    $query->innerJoin('private_message_thread__private_messages', 'thread_messages', 'thread_messages.entity_id = thread.id');
+    $query->innerJoin('private_messages', 'messages', 'messages.id = thread_messages.private_messages_target_id AND thread_history.delete_timestamp <= messages.created');
+    $query->condition('thread.id', $bannedThreadsQuery, 'NOT IN');
+    $query->orderBy('thread.updated', 'desc');
+    $query->range(0, 1);
+    $return = $query->execute()->fetchField();
+
+    return $return !== FALSE ? (int) $return : FALSE;
+  }
+
+  /**
+   * Retrieves a list of thread IDs for threads the user belongs to.
+   *
+   * @param \Drupal\user\UserInterface $user
+   *   The user whose most recently thread IDs should be retrieved.
+   * @param mixed $count
+   *   The number of thread IDs to retrieve or FALSE to retrieve them all.
+   * @param int $timestamp
+   *   A timestamp relative to which only thread IDs with an earlier timestamp
+   *   should be returned.
+   *
+   * @return array
+   *   An array of thread IDs if any threads exist.
+   */
+  protected function getThreadIdsForUser(UserInterface $user, $count = FALSE, $timestamp = FALSE): array {
+    $bannedThreadsQuery = $this->getBannedThreads($user->id());
+
+    $query = $this->database->select('private_message_threads', 'thread');
+    $query->addField('thread', 'id');
+    $query->addExpression('MAX(thread.updated)', 'last_updated');
+    $query->innerJoin('pm_thread_history', 'thread_history', 'thread_history.thread_id = thread.id AND thread_history.uid = :uid', [':uid' => $user->id()]);
+    $query->innerJoin('private_message_thread__members', 'thread_member', 'thread_member.entity_id = thread.id AND thread_member.members_target_id = :uid', [':uid' => $user->id()]);
+    $query->innerJoin('private_message_thread__private_messages', 'thread_messages', 'thread_messages.entity_id = thread.id');
+    $query->innerJoin('private_messages', 'messages', 'messages.id = thread_messages.private_messages_target_id AND thread_history.delete_timestamp <= messages.created');
+
+    $query->condition('thread.id', $bannedThreadsQuery, 'NOT IN');
+
+    if ($timestamp) {
+      $query->condition('updated', $timestamp, '<');
+    }
+
+    $query->groupBy('thread.id');
+    $query->orderBy('last_updated', 'desc');
+    $query->orderBy('thread.id');
+
+    if ($count > 0) {
+      $query->range(0, $count);
+    }
+
+    return $query->execute()->fetchCol();
+  }
+
+  /**
+   * Checks if a thread exists after with an ID greater than a given thread ID.
+   *
+   * @param \Drupal\user\UserInterface $user
+   *   The user for whom to check.
+   * @param int $timestamp
+   *   The timestamp to check against.
+   *
+   * @return bool
+   *   TRUE if a previous thread exists, FALSE if one doesn't.
+   */
+  protected function checkForNextThread(UserInterface $user, $timestamp): bool {
+    $query = 'SELECT DISTINCT(thread.id) ' .
+      'FROM {private_message_threads} AS thread ' .
+      'JOIN {pm_thread_history} pm_thread_history ' .
+      'ON pm_thread_history.thread_id = thread.id AND pm_thread_history.uid = :history_uid ' .
+      'JOIN {private_message_thread__members} AS thread_member ' .
+      'ON thread_member.entity_id = thread.id AND thread_member.members_target_id = :uid ' .
+      'JOIN {private_message_thread__private_messages} AS thread_messages ' .
+      'ON thread_messages.entity_id = thread.id ' .
+      'JOIN {private_messages} AS messages ' .
+      'ON messages.id = thread_messages.private_messages_target_id ' .
+      'WHERE pm_thread_history.delete_timestamp <= messages.created ' .
+      'AND thread.updated < :timestamp';
+    $vars = [
+      ':uid' => $user->id(),
+      ':history_uid' => $user->id(),
+      ':timestamp' => $timestamp,
+    ];
+
+    return (bool) $this->database->queryRange(
+      $query,
+      0, 1,
+      $vars
+    )->fetchField();
+  }
+
+  /**
+   * Retrieves a list of recently updated private message thread IDs.
+   *
+   * The last updated timestamp will also be returned. If any ids are provided
+   * in $existingThreadIds, the IDs of all threads that have been updated since
+   * the oldest updated timestamp for the given thread IDs will be returned.
+   * Otherwise the number of IDs returned will be the number provided for
+   * $count.
+   *
+   * @param array $existingThreadIds
+   *   An array of thread IDs to be compared against.
+   * @param int $count
+   *   The number of threads to return if no existing thread IDs were provided.
+   *
+   * @return array
+   *   An array, keyed by thread ID, with each element of the array containing
+   *   an object with the following two properties:
+   *   - id: The thread ID
+   *   - updated: The timestamp at which the thread was last updated
+   */
+  protected function getUpdatedInboxThreadIds(array $existingThreadIds, $count = FALSE): array {
+    $bannedThreadsQuery = $this->getBannedThreads($this->currentUser->id());
+
+    $query = $this->database->select('private_message_threads', 'thread');
+    $query->addField('thread', 'id');
+    $query->addField('thread', 'updated');
+    $query->innerJoin('pm_thread_history', 'thread_history', 'thread_history.thread_id = thread.id AND thread_history.uid = :uid', [':uid' => $this->currentUser->id()]);
+    $query->innerJoin('private_message_thread__members', 'thread_member', 'thread_member.entity_id = thread.id AND thread_member.members_target_id = :uid', [':uid' => $this->currentUser->id()]);
+    $query->innerJoin('private_message_thread__private_messages', 'thread_messages', 'thread_messages.entity_id = thread.id');
+    $query->innerJoin('private_messages', 'messages', 'messages.id = thread_messages.private_messages_target_id AND thread_history.delete_timestamp <= messages.created');
+    $query->condition('thread.id', $bannedThreadsQuery, 'NOT IN');
+    $query->orderBy('thread.updated', 'desc');
+    $query->groupBy('thread.id');
+
+    if (count($existingThreadIds)) {
+      $subquery = $this->database->select('private_message_threads', 'thread');
+      $subquery->addExpression('MIN(updated)');
+      $subquery->condition('id', $existingThreadIds, 'IN');
+
+      $query->condition('thread.updated', $subquery, '>=');
+    }
+    else {
+      $query->range(0, $count);
+    }
+
+    return $query->execute()->fetchAllAssoc('id');
+  }
+
+  /**
+   * Gets the current user's unread thread count.
+   *
+   * Retrieves the number of the current user's threads that have been updated
+   * since the last time this number was checked.
+   *
+   * @param int $uid
+   *   The user ID of the user whose count should be retrieved.
+   * @param int $lastCheckTimestamp
+   *   A UNIX timestamp indicating the time after which to check.
+   *
+   * @return int
+   *   The number of threads updated since the given timestamp
+   */
+  protected function getUnreadThreadCountHelper($uid, $lastCheckTimestamp): int {
+    $bannedThreadsQuery = $this->getBannedThreads($uid);
+
+    $query = $this->database->select('private_messages', 'message');
+    $query->addField('thread', 'id');
+    $query->innerJoin('private_message_thread__private_messages', 'thread_message', 'message.id = thread_message.private_messages_target_id');
+    $query->innerJoin('private_message_threads', 'thread', 'thread_message.entity_id = thread.id');
+    $query->innerJoin('pm_thread_history', 'thread_history', 'thread_history.thread_id = thread.id AND thread_history.access_timestamp < thread.updated AND thread_history.uid = :uid', [':uid' => $uid]);
+    $query->innerJoin('private_message_thread__members', 'thread_member', 'thread_member.entity_id = thread.id AND thread_member.members_target_id = :uid', [':uid' => $uid]);
+    $query->condition('thread.updated', $lastCheckTimestamp, '>');
+    $query->condition('message.created', $lastCheckTimestamp, '>');
+    $query->condition('message.owner', $uid, '<>');
+    $query->condition('thread.id', $bannedThreadsQuery, 'NOT IN');
+    $query->groupBy('thread.id');
+
+    return $query->countQuery()->execute()->fetchField();
+  }
+
+  /**
+   * Gets the current user's unread message count.
+   *
+   * Retrieves the number of the current user's messages that have been updated
+   * since the last time this number was checked.
+   *
+   * @param int $uid
+   *   The user ID of the user whose count should be retrieved.
+   * @param int $lastCheckTimestamp
+   *   A UNIX timestamp indicating the time after which to check.
+   *
+   * @return int
+   *   The number of threads updated since the given timestamp
+   */
+  protected function getUnreadMessageCountHelper($uid, $lastCheckTimestamp) {
+    $query = $this->database->select('private_messages', 'message');
+    $query->join(
+      'private_message_thread__private_messages',
+      'thread_message',
+      'message.id = thread_message.private_messages_target_id'
+    );
+    $query->join(
+      'private_message_threads',
+      'thread',
+      'thread_message.entity_id = thread.id'
+    );
+    $query->join(
+      'pm_thread_history',
+      'thread_history',
+      'thread_history.thread_id = thread.id AND thread_history.uid = :uid',
+      [':uid' => $uid]
+    );
+    $query->join(
+      'private_message_thread__members',
+      'thread_member',
+      'thread_member.entity_id = thread.id AND thread_member.members_target_id = :uid',
+      [':uid' => $uid]
+    );
+    $query
+      ->condition('thread.updated ', $lastCheckTimestamp, '>')
+      ->condition('message.created', $lastCheckTimestamp, '>')
+      ->condition('message.owner', $uid, '<>')
+      ->where('thread_history.access_timestamp < thread.updated');
+    $query = $query->countQuery();
+    return $query->execute()->fetchField();
+  }
+
+  /**
+   * Loads the thread id of the thread that a private message belongs to.
+   *
+   * @param \Drupal\private_message\Entity\PrivateMessageInterface $privateMessage
+   *   The private message for which the thread ID of the thread it belongs to
+   *   should be returned.
+   *
+   * @return int
+   *   The private message thread ID of the thread to which the private message
+   *   belongs.
+   */
+  protected function getThreadIdFromMessage(PrivateMessageInterface $privateMessage): int {
+    $query = $this->database->select('private_message_threads', 'thread');
+    $query->fields('thread', ['id']);
+    $query->join('private_message_thread__private_messages',
+      'messages',
+      'messages.entity_id = thread.id AND messages.private_messages_target_id = :message_id',
+      [':message_id' => $privateMessage->id()]
+    );
+    return $query
+      ->range(0, 1)
+      ->execute()
+      ->fetchField();
+  }
+
+  /**
+   * Returns query object of banned threads for the user.
+   *
+   * @param int $user_id
+   *   The user id.
+   *
+   * @return \Drupal\Core\Database\Query\SelectInterface
+   *   The select query object.
+   */
+  protected function getBannedThreads(int $user_id): SelectInterface {
+    // Get the list of banned users for this user.
+    $subquery = $this->database->select('private_message_ban', 'pmb');
+    $subquery->addField('pmb', 'target');
+    $subquery->condition('pmb.owner', $user_id);
+
+    // Get list of threads with banned users.
+    $bannedThreadsQuery = $this->database->select('private_message_thread__members', 'thread_member');
+    $bannedThreadsQuery->addField('thread_member', 'entity_id');
+    $bannedThreadsQuery->condition('thread_member.members_target_id', $subquery, 'IN');
+    $bannedThreadsQuery->groupBy('entity_id');
+
+    return $bannedThreadsQuery;
+  }
+
 }
diff --git a/src/Service/PrivateMessageServiceInterface.php b/src/Service/PrivateMessageServiceInterface.php
index 785c4108..f2a40a34 100644
--- a/src/Service/PrivateMessageServiceInterface.php
+++ b/src/Service/PrivateMessageServiceInterface.php
@@ -191,4 +191,20 @@ interface PrivateMessageServiceInterface {
    */
   public function getThreadIds();
 
+  /**
+   * Get the current user's unread message count by thread id.
+   *
+   * Retrieves the number of the current user's messages that have been updated
+   * since user last thread access.
+   *
+   * @param int $uid
+   *   The user ID of the user whose count should be retrieved.
+   * @param int $thread_id
+   *   The thread ID which messages should be checked.
+   *
+   * @return int
+   *   The number of threads updated since the given timestamp
+   */
+  public function getThreadUnreadMessageCount($uid, $thread_id);
+
 }
-- 
GitLab


From b5f738084072628fb28fb7ab0ef3f1109d9c3c9a Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Fri, 29 Nov 2024 00:03:11 +0200
Subject: [PATCH 15/30] Strict type form classes

---
 src/Form/AdminUninstallForm.php               | 15 +++---
 src/Form/BanUserForm.php                      |  2 +
 src/Form/ConfigForm.php                       | 52 ++++++++++---------
 src/Form/ConfirmBanUserForm.php               | 13 +++--
 src/Form/ConfirmUnbanUserForm.php             | 13 +++--
 src/Form/PrivateMessageBanForm.php            |  6 +--
 src/Form/PrivateMessageDeleteForm.php         |  4 +-
 src/Form/PrivateMessageForm.php               | 43 ++++++++-------
 ...eMessageThreadClearPersonalHistoryForm.php | 12 +++--
 src/Form/PrivateMessageThreadDeleteForm.php   | 12 +++--
 ...ivateMessageConfigFormManagerInterface.php |  4 +-
 11 files changed, 101 insertions(+), 75 deletions(-)

diff --git a/src/Form/AdminUninstallForm.php b/src/Form/AdminUninstallForm.php
index 748f7664..97fea4fe 100644
--- a/src/Form/AdminUninstallForm.php
+++ b/src/Form/AdminUninstallForm.php
@@ -1,9 +1,12 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Form;
 
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
 use Drupal\private_message\Service\PrivateMessageUninstallerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -20,7 +23,7 @@ class AdminUninstallForm extends ConfirmFormBase {
   /**
    * {@inheritdoc}
    */
-  public static function create(ContainerInterface $container) {
+  public static function create(ContainerInterface $container): self {
     return new static(
       $container->get('private_message.uninstaller')
     );
@@ -29,35 +32,35 @@ class AdminUninstallForm extends ConfirmFormBase {
   /**
    * {@inheritdoc}
    */
-  public function getFormId() {
+  public function getFormId(): string {
     return 'private_message_admin_uninstall_form';
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getQuestion() {
+  public function getQuestion(): TranslatableMarkup {
     return $this->t('Are you sure you want to delete all private message content from the system?');
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getCancelUrl() {
+  public function getCancelUrl(): Url {
     return Url::fromRoute('private_message.admin_config.uninstall');
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getDescription() {
+  public function getDescription(): TranslatableMarkup|string {
     return $this->t('Clicking the button below will delete all private message content from the system, allowing the module to be uninstalled.') . '<br><strong>' . $this->t('THIS ACTION CANNOT BE REVERSED') . '</strong>';
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, FormStateInterface $form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state): void {
     $this->privateMessageUninstaller->initiateBatch();
 
     $this->messenger()
diff --git a/src/Form/BanUserForm.php b/src/Form/BanUserForm.php
index fe585c1c..b73c88ce 100644
--- a/src/Form/BanUserForm.php
+++ b/src/Form/BanUserForm.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Form;
 
 use Drupal\Core\DependencyInjection\AutowireTrait;
diff --git a/src/Form/ConfigForm.php b/src/Form/ConfigForm.php
index 79dcc4dd..59478cbe 100644
--- a/src/Form/ConfigForm.php
+++ b/src/Form/ConfigForm.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Form;
 
 use Drupal\Core\Config\ConfigFactoryInterface;
@@ -50,14 +52,14 @@ class ConfigForm extends ConfigFormBase {
   /**
    * {@inheritdoc}
    */
-  public function getFormId() {
+  public function getFormId(): string {
     return 'private_message_config_form';
   }
 
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $formState) {
+  public function buildForm(array $form, FormStateInterface $form_state): array {
     $config = $this->config('private_message.settings');
 
     $form['pm_core'] = [
@@ -226,60 +228,60 @@ class ConfigForm extends ConfigFormBase {
         '#tree' => TRUE,
         '#open' => TRUE,
       ];
-      foreach ($instance->buildForm($formState) as $key => $element) {
+      foreach ($instance->buildForm($form_state) as $key => $element) {
         $form[$instance->getId()][$key] = $element;
       }
     }
 
-    return parent::buildForm($form, $formState);
+    return parent::buildForm($form, $form_state);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, FormStateInterface $formState) {
+  public function validateForm(array &$form, FormStateInterface $form_state): void {
     $definitions = $this->privateMessageConfigFormManager->getDefinitions();
     foreach ($definitions as $definition) {
       $instance = $this->privateMessageConfigFormManager->createInstance($definition['id']);
-      $instance->validateForm($form, $formState);
+      $instance->validateForm($form, $form_state);
     }
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, FormStateInterface $formState) {
+  public function submitForm(array &$form, FormStateInterface $form_state): void {
     $this->config('private_message.settings')
-      ->set('enable_notifications', (bool) $formState->getValue('enable_notifications'))
-      ->set('notify_by_default', (bool) $formState->getValue('notify_by_default'))
-      ->set('notify_when_using', (string) $formState->getValue('notify_when_using'))
-      ->set('number_of_seconds_considered_away', (int) $formState->getValue('number_of_seconds_considered_away'))
-      ->set('hide_recipient_field_when_prefilled', (bool) $formState->getValue('hide_recipient_field_when_prefilled'))
-      ->set('create_message_label', $formState->getValue('create_message_label'))
-      ->set('save_message_label', $formState->getValue('save_message_label'))
-      ->set('ban_mode', $formState->getValue('ban_mode'))
-      ->set('ban_label', $formState->getValue('ban_label'))
-      ->set('unban_label', $formState->getValue('unban_label'))
-      ->set('ban_page_label', $formState->getValue('ban_page_label'))
-      ->set('ban_message', $formState->getValue('ban_message'))
-      ->set('autofocus_enable', (bool) $formState->getValue('autofocus_enable'))
-      ->set('keys_send', $formState->getValue('keys_send'))
-      ->set('remove_css', (bool) $formState->getValue('remove_css'))
+      ->set('enable_notifications', (bool) $form_state->getValue('enable_notifications'))
+      ->set('notify_by_default', (bool) $form_state->getValue('notify_by_default'))
+      ->set('notify_when_using', (string) $form_state->getValue('notify_when_using'))
+      ->set('number_of_seconds_considered_away', (int) $form_state->getValue('number_of_seconds_considered_away'))
+      ->set('hide_recipient_field_when_prefilled', (bool) $form_state->getValue('hide_recipient_field_when_prefilled'))
+      ->set('create_message_label', $form_state->getValue('create_message_label'))
+      ->set('save_message_label', $form_state->getValue('save_message_label'))
+      ->set('ban_mode', $form_state->getValue('ban_mode'))
+      ->set('ban_label', $form_state->getValue('ban_label'))
+      ->set('unban_label', $form_state->getValue('unban_label'))
+      ->set('ban_page_label', $form_state->getValue('ban_page_label'))
+      ->set('ban_message', $form_state->getValue('ban_message'))
+      ->set('autofocus_enable', (bool) $form_state->getValue('autofocus_enable'))
+      ->set('keys_send', $form_state->getValue('keys_send'))
+      ->set('remove_css', (bool) $form_state->getValue('remove_css'))
       ->save();
 
     $definitions = $this->privateMessageConfigFormManager->getDefinitions();
     foreach ($definitions as $definition) {
       $instance = $this->privateMessageConfigFormManager->createInstance($definition['id']);
-      $instance->submitForm($formState->getValue($instance->getId()));
+      $instance->submitForm($form_state->getValue($instance->getId()));
     }
 
-    parent::submitForm($form, $formState);
+    parent::submitForm($form, $form_state);
   }
 
   /**
    * {@inheritdoc}
    */
-  protected function getEditableConfigNames() {
+  protected function getEditableConfigNames(): array {
     return [
       'private_message.settings',
     ];
diff --git a/src/Form/ConfirmBanUserForm.php b/src/Form/ConfirmBanUserForm.php
index 37473b99..1aaaca27 100644
--- a/src/Form/ConfirmBanUserForm.php
+++ b/src/Form/ConfirmBanUserForm.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Form;
 
 use Drupal\Core\DependencyInjection\AutowireTrait;
@@ -7,6 +9,7 @@ use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountProxyInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
 use Drupal\private_message\Model\BlockType;
 use Drupal\private_message\Service\PrivateMessageBanManagerInterface;
@@ -48,7 +51,7 @@ class ConfirmBanUserForm extends ConfirmFormBase {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, FormStateInterface $form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state): void {
     // Add a security if the user id is unknown.
     if (empty($this->user)) {
       $form_state->setError($form, $this->t('The user id is unknown.'));
@@ -64,7 +67,7 @@ class ConfirmBanUserForm extends ConfirmFormBase {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, FormStateInterface $form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state): void {
     $form_state->setRedirect('private_message.private_message_page');
 
     // If user is already banned, do nothing.
@@ -81,14 +84,14 @@ class ConfirmBanUserForm extends ConfirmFormBase {
   /**
    * {@inheritdoc}
    */
-  public function getQuestion() {
+  public function getQuestion(): TranslatableMarkup {
     return $this->t('Are you sure you want to block user <em>%user</em>?', ['%user' => $this->user->getDisplayName()]);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getDescription() {
+  public function getDescription(): TranslatableMarkup {
     $config = $this->config('private_message.settings');
 
     if ($config->get('ban_mode') === BlockType::Passive->value) {
@@ -102,7 +105,7 @@ class ConfirmBanUserForm extends ConfirmFormBase {
   /**
    * {@inheritdoc}
    */
-  public function getCancelUrl() {
+  public function getCancelUrl(): Url {
     return new Url('private_message.ban_page');
   }
 
diff --git a/src/Form/ConfirmUnbanUserForm.php b/src/Form/ConfirmUnbanUserForm.php
index d5b4fed8..cf7c84f2 100644
--- a/src/Form/ConfirmUnbanUserForm.php
+++ b/src/Form/ConfirmUnbanUserForm.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Form;
 
 use Drupal\Core\DependencyInjection\AutowireTrait;
@@ -7,6 +9,7 @@ use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountProxyInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
 use Drupal\private_message\Service\PrivateMessageBanManagerInterface;
 use Drupal\user\UserInterface;
@@ -47,7 +50,7 @@ class ConfirmUnbanUserForm extends ConfirmFormBase {
   /**
    * {@inheritdoc}
    */
-  public function validateForm(array &$form, FormStateInterface $form_state) {
+  public function validateForm(array &$form, FormStateInterface $form_state): void {
     // Add a security if the user id is unknown.
     if (empty($this->user)) {
       $form_state->setError($form, $this->t('The user id is unknown.'));
@@ -62,7 +65,7 @@ class ConfirmUnbanUserForm extends ConfirmFormBase {
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, FormStateInterface $form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state): void {
     $form_state->setRedirect('private_message.private_message_page');
 
     // If user not banned, do nothing.
@@ -79,7 +82,7 @@ class ConfirmUnbanUserForm extends ConfirmFormBase {
   /**
    * {@inheritdoc}
    */
-  public function getQuestion() {
+  public function getQuestion(): TranslatableMarkup {
     return $this->t('Are you sure you want to unblock user <em>%user</em>?', [
       '%user' => $this->user->getDisplayName(),
     ]);
@@ -88,14 +91,14 @@ class ConfirmUnbanUserForm extends ConfirmFormBase {
   /**
    * {@inheritdoc}
    */
-  public function getDescription() {
+  public function getDescription(): TranslatableMarkup {
     return $this->t('By confirming, you will be able to send messages to this user.');
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getCancelUrl() {
+  public function getCancelUrl(): Url {
     return new Url('private_message.ban_page');
   }
 
diff --git a/src/Form/PrivateMessageBanForm.php b/src/Form/PrivateMessageBanForm.php
index 01992c69..a945807a 100644
--- a/src/Form/PrivateMessageBanForm.php
+++ b/src/Form/PrivateMessageBanForm.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Form;
 
 use Drupal\Core\Entity\ContentEntityForm;
@@ -7,15 +9,13 @@ use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Form controller for Private Message Ban edit forms.
- *
- * @ingroup private_message
  */
 class PrivateMessageBanForm extends ContentEntityForm {
 
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, FormStateInterface $form_state) {
+  public function save(array $form, FormStateInterface $form_state): int {
     $status = parent::save($form, $form_state);
 
     switch ($status) {
diff --git a/src/Form/PrivateMessageDeleteForm.php b/src/Form/PrivateMessageDeleteForm.php
index a7e34722..335ef645 100644
--- a/src/Form/PrivateMessageDeleteForm.php
+++ b/src/Form/PrivateMessageDeleteForm.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Form;
 
 use Drupal\Core\Entity\ContentEntityDeleteForm;
@@ -19,7 +21,7 @@ class PrivateMessageDeleteForm extends ContentEntityDeleteForm {
   /**
    * {@inheritdoc}
    */
-  protected function logDeletionMessage() {
+  protected function logDeletionMessage(): void {
     $this->logger('private_message')
       ->notice('@user deleted a private message.', [
         '@user' => $this->currentUser()->getDisplayName(),
diff --git a/src/Form/PrivateMessageForm.php b/src/Form/PrivateMessageForm.php
index 6b08d570..5d9f5d50 100644
--- a/src/Form/PrivateMessageForm.php
+++ b/src/Form/PrivateMessageForm.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Form;
 
 use Drupal\Component\Datetime\TimeInterface;
@@ -40,10 +42,8 @@ class PrivateMessageForm extends ContentEntityForm {
 
   /**
    * A unique instance identifier for the form.
-   *
-   * @var int
    */
-  protected $formId;
+  protected string $formId = '';
 
   public function __construct(
     EntityRepositoryInterface $entityRepository,
@@ -67,15 +67,21 @@ class PrivateMessageForm extends ContentEntityForm {
    *
    * @param mixed $id
    *   An ID required to be unique each time the form is called on a page.
+   *
+   * @deprecated in private_message:4.0.0 and is removed from
+   *   private_message:5.0.0. No replacement is provided.
+   *
+   * @see https://www.drupal.org/node/3490530
    */
   public function setFormId($id) {
+    @trigger_error(__METHOD__ . '() is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. No replacement is provided. See https://www.drupal.org/node/3490530', E_USER_DEPRECATED);
     $this->formId = Html::escape($id);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getFormId() {
+  public function getFormId(): string {
     $form_id = parent::getFormId();
 
     if ($this->formId) {
@@ -88,7 +94,7 @@ class PrivateMessageForm extends ContentEntityForm {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $form_state, ?PrivateMessageThreadInterface $privateMessageThread = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, ?PrivateMessageThreadInterface $privateMessageThread = NULL): array {
     $form = parent::buildForm($form, $form_state);
 
     if ($privateMessageThread) {
@@ -198,7 +204,7 @@ class PrivateMessageForm extends ContentEntityForm {
   }
 
   /**
-   * Validate members that have been added to a private message thread.
+   * Validates members that have been added to a private message thread.
    *
    * Validates that submitted members have permission to use the Private
    * message system. This validation is not added automatically, as the members
@@ -209,7 +215,7 @@ class PrivateMessageForm extends ContentEntityForm {
    *
    * @see \Drupal\private_message\Entity\PrivateMessageThead::baseFieldDefinitions
    */
-  public function validateMembers(array &$form, FormStateInterface $formState) {
+  public function validateMembers(array &$form, FormStateInterface $formState): void {
     // The members form element was loaded from the PrivateMessageThread entity
     // type. As it is not a part of the PrivateMessage entity, for which this
     // form is built, the constraints that are a part of the field on the
@@ -272,8 +278,7 @@ class PrivateMessageForm extends ContentEntityForm {
   /**
    * Validates that the current user isn't replying to a banned member.
    */
-  public function validateBannedMembers(array &$form, FormStateInterface $formState) {
-
+  public function validateBannedMembers(array &$form, FormStateInterface $formState): void {
     /** @var \Drupal\private_message\Entity\PrivateMessageThread|null $privateMessageThread */
     $privateMessageThread = $formState->get('thread');
     $threadMembers = $privateMessageThread ? $privateMessageThread->getMemberIds() : [];
@@ -292,7 +297,7 @@ class PrivateMessageForm extends ContentEntityForm {
    *
    * Re-render form after submission, so user could write new message.
    */
-  public function ajaxCallback(array $form, FormStateInterface $formState) {
+  public function ajaxCallback(array $form, FormStateInterface $formState): AjaxResponse {
     $response = new AjaxResponse();
 
     // Return early if there are any form validation errors.
@@ -345,22 +350,22 @@ class PrivateMessageForm extends ContentEntityForm {
   /**
    * After build callback for the Private Message Form.
    */
-  public function afterBuild(array $form, FormStateInterface $formState) {
-    $form['message']['widget'][0]['format']['#attributes']['class'][] = 'hidden';
-    return $form;
+  public function afterBuild(array $element, FormStateInterface $form_state): array {
+    $element['message']['widget'][0]['format']['#attributes']['class'][] = 'hidden';
+    return $element;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function save(array $form, FormStateInterface $formState) {
-    $status = parent::save($form, $formState);
+  public function save(array $form, FormStateInterface $form_state): int {
+    $status = parent::save($form, $form_state);
 
     /** @var \Drupal\private_message\Entity\PrivateMessageThreadInterface $entity */
-    $entity = $formState->get('pmt_entity');
+    $entity = $form_state->get('pmt_entity');
 
     /** @var \Drupal\private_message\Entity\PrivateMessageThreadInterface $private_message_thread */
-    $private_message_thread = $formState->get('thread');
+    $private_message_thread = $form_state->get('thread');
     if (!$private_message_thread) {
       // Generate an array containing the members of the thread.
       $current_user = $this->entityTypeManager
@@ -390,11 +395,11 @@ class PrivateMessageForm extends ContentEntityForm {
     $this->privateMessageThreadManager->saveThread($this->entity, $private_message_thread->getMembers(), $private_message_thread);
 
     // Save the thread to the form state.
-    $formState->set('private_message_thread', $private_message_thread);
+    $form_state->set('private_message_thread', $private_message_thread);
 
     // Send the user to the private message page. As this thread is the newest,
     // it wll be at the top of the list.
-    $formState->setRedirect('entity.private_message_thread.canonical', ['private_message_thread' => $private_message_thread->id()]);
+    $form_state->setRedirect('entity.private_message_thread.canonical', ['private_message_thread' => $private_message_thread->id()]);
 
     return $status;
   }
diff --git a/src/Form/PrivateMessageThreadClearPersonalHistoryForm.php b/src/Form/PrivateMessageThreadClearPersonalHistoryForm.php
index dd874040..c141083e 100644
--- a/src/Form/PrivateMessageThreadClearPersonalHistoryForm.php
+++ b/src/Form/PrivateMessageThreadClearPersonalHistoryForm.php
@@ -1,9 +1,12 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Form;
 
 use Drupal\Core\Entity\ContentEntityConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
 
 /**
@@ -16,7 +19,7 @@ class PrivateMessageThreadClearPersonalHistoryForm extends ContentEntityConfirmF
   /**
    * {@inheritdoc}
    */
-  public function getQuestion() {
+  public function getQuestion(): TranslatableMarkup {
     $members = $this->getEntity()->getMembers();
     $member_names = [];
     foreach ($members as $member) {
@@ -31,25 +34,24 @@ class PrivateMessageThreadClearPersonalHistoryForm extends ContentEntityConfirmF
   /**
    * {@inheritdoc}
    */
-  public function getCancelUrl() {
+  public function getCancelUrl(): Url {
     return Url::fromRoute('entity.private_message_thread.canonical', ['private_message_thread' => $this->getEntity()->id()]);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getConfirmText() {
+  public function getConfirmText(): TranslatableMarkup {
     return $this->t('Clear history');
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, FormStateInterface $form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state): void {
     parent::submitForm($form, $form_state);
 
     $this->getEntity()->clearAccountHistory($this->currentUser());
-
     $form_state->setRedirect('private_message.private_message_page');
   }
 
diff --git a/src/Form/PrivateMessageThreadDeleteForm.php b/src/Form/PrivateMessageThreadDeleteForm.php
index 897d23d7..1e7ed19f 100644
--- a/src/Form/PrivateMessageThreadDeleteForm.php
+++ b/src/Form/PrivateMessageThreadDeleteForm.php
@@ -1,9 +1,12 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Form;
 
 use Drupal\Core\Entity\ContentEntityConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
 
 /**
@@ -16,7 +19,7 @@ class PrivateMessageThreadDeleteForm extends ContentEntityConfirmFormBase {
   /**
    * {@inheritdoc}
    */
-  public function getQuestion() {
+  public function getQuestion(): TranslatableMarkup {
     $members = $this->getEntity()->getMembers();
     $member_names = [];
     foreach ($members as $member) {
@@ -31,25 +34,24 @@ class PrivateMessageThreadDeleteForm extends ContentEntityConfirmFormBase {
   /**
    * {@inheritdoc}
    */
-  public function getCancelUrl() {
+  public function getCancelUrl(): Url {
     return Url::fromRoute('entity.private_message_thread.canonical', ['private_message_thread' => $this->getEntity()->id()]);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getConfirmText() {
+  public function getConfirmText(): TranslatableMarkup {
     return $this->t('Delete thread');
   }
 
   /**
    * {@inheritdoc}
    */
-  public function submitForm(array &$form, FormStateInterface $form_state) {
+  public function submitForm(array &$form, FormStateInterface $form_state): void {
     parent::submitForm($form, $form_state);
 
     $this->getEntity()->delete();
-
     $form_state->setRedirect('private_message.private_message_page');
   }
 
diff --git a/src/PluginManager/PrivateMessageConfigFormManagerInterface.php b/src/PluginManager/PrivateMessageConfigFormManagerInterface.php
index eb139b64..7ac5d621 100644
--- a/src/PluginManager/PrivateMessageConfigFormManagerInterface.php
+++ b/src/PluginManager/PrivateMessageConfigFormManagerInterface.php
@@ -4,7 +4,9 @@ declare(strict_types=1);
 
 namespace Drupal\private_message\PluginManager;
 
+use Drupal\Component\Plugin\PluginManagerInterface;
+
 /**
  * Plugin Manager to detect PrivateMessageConfigForm plugins.
  */
-interface PrivateMessageConfigFormManagerInterface {}
+interface PrivateMessageConfigFormManagerInterface extends PluginManagerInterface {}
-- 
GitLab


From fae7996599ac2ab551ac4600a845ca188d410b13 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Fri, 29 Nov 2024 00:28:02 +0200
Subject: [PATCH 16/30] Strict type blocks, formatters, widgets

---
 src/Plugin/Block/PrivateMessageActionsBlock.php   |  6 ++++--
 src/Plugin/Block/PrivateMessageInboxBlock.php     |  4 +++-
 .../Block/PrivateMessageNotificationBlock.php     |  6 ++++--
 .../PrivateMessageThreadMemberFormatter.php       |  4 +++-
 ...PrivateMessageThreadMembersNumberFormatter.php | 15 +++++++--------
 .../PrivateMessageThreadMessageFormatter.php      |  8 +++++---
 .../PrivateMessageThreadMemberWidget.php          |  7 +++----
 src/Plugin/Menu/PrivateMessageTab.php             |  2 ++
 8 files changed, 31 insertions(+), 21 deletions(-)

diff --git a/src/Plugin/Block/PrivateMessageActionsBlock.php b/src/Plugin/Block/PrivateMessageActionsBlock.php
index d19ee209..b4f88a20 100644
--- a/src/Plugin/Block/PrivateMessageActionsBlock.php
+++ b/src/Plugin/Block/PrivateMessageActionsBlock.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\Block;
 
 use Drupal\Core\Access\AccessResult;
@@ -39,7 +41,7 @@ class PrivateMessageActionsBlock extends BlockBase implements ContainerFactoryPl
   /**
    * {@inheritdoc}
    */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): PrivateMessageActionsBlock {
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
     return new static(
       $configuration,
       $plugin_id,
@@ -60,7 +62,7 @@ class PrivateMessageActionsBlock extends BlockBase implements ContainerFactoryPl
   /**
    * {@inheritdoc}
    */
-  public function build() {
+  public function build(): array {
     if (!$this->currentUser->hasPermission('use private messaging system')) {
       return [];
     }
diff --git a/src/Plugin/Block/PrivateMessageInboxBlock.php b/src/Plugin/Block/PrivateMessageInboxBlock.php
index 4aa05288..5ab73635 100644
--- a/src/Plugin/Block/PrivateMessageInboxBlock.php
+++ b/src/Plugin/Block/PrivateMessageInboxBlock.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\Block;
 
 use Drupal\Core\Access\AccessResult;
@@ -49,7 +51,7 @@ class PrivateMessageInboxBlock extends BlockBase implements BlockPluginInterface
   /**
    * {@inheritdoc}
    */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): PrivateMessageInboxBlock {
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
     return new static(
       $configuration,
       $plugin_id,
diff --git a/src/Plugin/Block/PrivateMessageNotificationBlock.php b/src/Plugin/Block/PrivateMessageNotificationBlock.php
index 99ace3c4..08a74cb1 100644
--- a/src/Plugin/Block/PrivateMessageNotificationBlock.php
+++ b/src/Plugin/Block/PrivateMessageNotificationBlock.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\Block;
 
 use Drupal\Core\Access\AccessResult;
@@ -47,7 +49,7 @@ class PrivateMessageNotificationBlock extends BlockBase implements BlockPluginIn
   /**
    * {@inheritdoc}
    */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): PrivateMessageNotificationBlock {
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
     return new static(
       $configuration,
       $plugin_id,
@@ -117,7 +119,7 @@ class PrivateMessageNotificationBlock extends BlockBase implements BlockPluginIn
   /**
    * {@inheritdoc}
    */
-  public function getCacheTags() {
+  public function getCacheTags(): array {
     $tags = [
       'private_message:status:uid:' . $this->currentUser->id(),
       // This cache tag is @deprecated, since we have added the cache tag above.
diff --git a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMemberFormatter.php b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMemberFormatter.php
index f1b7e6ea..d65267a5 100644
--- a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMemberFormatter.php
+++ b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMemberFormatter.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\Field\FieldFormatter;
 
 use Drupal\Component\Render\FormattableMarkup;
@@ -48,7 +50,7 @@ class PrivateMessageThreadMemberFormatter extends FormatterBase implements Conta
   /**
    * {@inheritdoc}
    */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): PrivateMessageThreadMemberFormatter {
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
     return new static(
       $plugin_id,
       $plugin_definition,
diff --git a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMembersNumberFormatter.php b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMembersNumberFormatter.php
index 746d9968..fbe3d8ef 100644
--- a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMembersNumberFormatter.php
+++ b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMembersNumberFormatter.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\Field\FieldFormatter;
 
 use Drupal\Core\Field\Attribute\FieldFormatter;
@@ -25,25 +27,23 @@ class PrivateMessageThreadMembersNumberFormatter extends FormatterBase implement
   /**
    * {@inheritdoc}
    */
-  public static function isApplicable(FieldDefinitionInterface $field_definition) {
+  public static function isApplicable(FieldDefinitionInterface $field_definition): bool {
     return ($field_definition->getFieldStorageDefinition()->getTargetEntityTypeId() == 'private_message_thread' && $field_definition->getFieldStorageDefinition()->getSetting('target_type') == 'user');
   }
 
   /**
    * {@inheritdoc}
    */
-  public function settingsSummary() {
+  public function settingsSummary(): array {
     $summary = [];
-
     $summary['members_number_suffix'] = $this->t('The members number suffix text: %members_number_suffix. Example: 5 %members_number_suffix', ['%members_number_suffix' => $this->getSetting('members_number_suffix')]);
-
     return $summary;
   }
 
   /**
    * {@inheritdoc}
    */
-  public static function defaultSettings() {
+  public static function defaultSettings(): array {
     return [
       'members_number_suffix' => 'users',
     ] + parent::defaultSettings();
@@ -52,7 +52,7 @@ class PrivateMessageThreadMembersNumberFormatter extends FormatterBase implement
   /**
    * {@inheritdoc}
    */
-  public function settingsForm(array $form, FormStateInterface $form_state) {
+  public function settingsForm(array $form, FormStateInterface $form_state): array {
     $element = [];
 
     $element['members_number_suffix'] = [
@@ -67,8 +67,7 @@ class PrivateMessageThreadMembersNumberFormatter extends FormatterBase implement
   /**
    * {@inheritdoc}
    */
-  public function viewElements(FieldItemListInterface $items, $langcode) {
-
+  public function viewElements(FieldItemListInterface $items, $langcode): array {
     $users_num = count($items);
     $suffix = $this->getSetting('members_number_suffix');
 
diff --git a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php
index 3e8aac02..44889593 100644
--- a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php
+++ b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\Field\FieldFormatter;
 
 use Drupal\Core\Access\CsrfTokenGenerator;
@@ -52,7 +54,7 @@ class PrivateMessageThreadMessageFormatter extends FormatterBase implements Cont
   /**
    * {@inheritdoc}
    */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): PrivateMessageThreadMessageFormatter {
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
     return new static(
       $plugin_id,
       $plugin_definition,
@@ -253,7 +255,7 @@ class PrivateMessageThreadMessageFormatter extends FormatterBase implements Cont
    * @param string $value
    *   The value to be translated.
    *
-   * @return mixed
+   * @return \Drupal\Core\StringTranslation\TranslatableMarkup|string
    *   - If a translated value exists for the given type/value combination, a
    *     \Drupal\Core\StringTranslation\TranslatableMarkup object containing the
    *     translated value is returned.
@@ -261,7 +263,7 @@ class PrivateMessageThreadMessageFormatter extends FormatterBase implements Cont
    *     a string is returned.
    *   - If the type does not exist, the untranslated value is returned.
    */
-  private function translateKey($type, $value) {
+  private function translateKey(string $type, string $value): TranslatableMarkup|string {
     if ($type == 'order') {
       $keys = [
         'asc' => $this->t('Ascending'),
diff --git a/src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php b/src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php
index 25d8f4c9..c429729e 100644
--- a/src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php
+++ b/src/Plugin/Field/FieldWidget/PrivateMessageThreadMemberWidget.php
@@ -49,7 +49,7 @@ class PrivateMessageThreadMemberWidget extends EntityReferenceAutocompleteWidget
   /**
    * {@inheritdoc}
    */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): PrivateMessageThreadMemberWidget {
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
     return new static(
       $plugin_id,
       $plugin_definition,
@@ -90,7 +90,6 @@ class PrivateMessageThreadMemberWidget extends EntityReferenceAutocompleteWidget
     $summary = parent::settingsSummary();
 
     unset($summary[0]);
-
     $summary[] = $this->t('Maximum thread members: @count', ['@count' => $this->getSetting('max_members')]);
 
     return $summary;
@@ -185,8 +184,8 @@ class PrivateMessageThreadMemberWidget extends EntityReferenceAutocompleteWidget
   /**
    * {@inheritdoc}
    */
-  public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
-    return $values['target_id'];
+  public function massageFormValues(array $values, array $form, FormStateInterface $form_state): array {
+    return $values['target_id'] ?? [];
   }
 
 }
diff --git a/src/Plugin/Menu/PrivateMessageTab.php b/src/Plugin/Menu/PrivateMessageTab.php
index b56b9924..56fa5607 100644
--- a/src/Plugin/Menu/PrivateMessageTab.php
+++ b/src/Plugin/Menu/PrivateMessageTab.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\Menu;
 
 use Drupal\Core\Menu\LocalTaskDefault;
-- 
GitLab


From 9b15fb79a568b0f86ff0c3b756ff47ef47c640e6 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Fri, 29 Nov 2024 11:02:13 +0200
Subject: [PATCH 17/30] Finalize plugins strict typing

---
 .../PrivateMessageThreadMessageFormatter.php         | 10 +++++-----
 .../PrivateMessageConfigFormBase.php                 |  8 +++++---
 .../PrivateMessageConfigFormPluginInterface.php      |  8 +++++---
 src/Plugin/RulesAction/SendPrivateMessage.php        |  6 ++++--
 .../PrivateMessageThreadMemberConstraint.php         |  2 ++
 ...PrivateMessageThreadMemberConstraintValidator.php |  4 +++-
 .../Validation/Constraint/UniqueBanConstraint.php    |  2 ++
 .../Constraint/UniqueBanConstraintValidator.php      |  4 +++-
 .../field/PrivateMessageThreadHasNewMessage.php      |  9 ++++++---
 .../field/PrivateMessageThreadMessagesCount.php      |  8 ++++----
 .../field/PrivateMessageThreadNewMessagesCount.php   | 10 ++++++----
 .../filter/PrivateMessageThreadCleanHistory.php      | 12 ++++++++----
 .../views/filter/PrivateMessageThreadIsUnread.php    | 12 ++++++++----
 13 files changed, 61 insertions(+), 34 deletions(-)

diff --git a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php
index 44889593..a2b5b25e 100644
--- a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php
+++ b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php
@@ -75,7 +75,7 @@ class PrivateMessageThreadMessageFormatter extends FormatterBase implements Cont
    * {@inheritdoc}
    */
   public static function isApplicable(FieldDefinitionInterface $field_definition): bool {
-    return ($field_definition->getFieldStorageDefinition()->getTargetEntityTypeId() == 'private_message_thread' && $field_definition->getFieldStorageDefinition()->getSetting('target_type') == 'private_message');
+    return $field_definition->getFieldStorageDefinition()->getTargetEntityTypeId() === 'private_message_thread' && $field_definition->getFieldStorageDefinition()->getSetting('target_type') === 'private_message';
   }
 
   /**
@@ -98,7 +98,7 @@ class PrivateMessageThreadMessageFormatter extends FormatterBase implements Cont
    */
   public function settingsSummary(): array {
     $summary = [];
-    $settings = $this->getPrivateMessageSettings();
+    $settings = $this->getSettings();
 
     $summary['message_count'] = $this->t('Number of threads to show on load: @count', ['@count' => $settings['message_count']]);
     $summary['ajax_previous_load_count'] = $this->t('Number of threads to show when clicking load previous: @count', ['@count' => $settings['ajax_previous_load_count']]);
@@ -252,10 +252,10 @@ class PrivateMessageThreadMessageFormatter extends FormatterBase implements Cont
    *
    * @param string $type
    *   The type of string being translated.
-   * @param string $value
+   * @param string|null $value
    *   The value to be translated.
    *
-   * @return \Drupal\Core\StringTranslation\TranslatableMarkup|string
+   * @return \Drupal\Core\StringTranslation\TranslatableMarkup|string|null
    *   - If a translated value exists for the given type/value combination, a
    *     \Drupal\Core\StringTranslation\TranslatableMarkup object containing the
    *     translated value is returned.
@@ -263,7 +263,7 @@ class PrivateMessageThreadMessageFormatter extends FormatterBase implements Cont
    *     a string is returned.
    *   - If the type does not exist, the untranslated value is returned.
    */
-  private function translateKey(string $type, string $value): TranslatableMarkup|string {
+  private function translateKey(string $type, ?string $value): TranslatableMarkup|string|null {
     if ($type == 'order') {
       $keys = [
         'asc' => $this->t('Ascending'),
diff --git a/src/Plugin/PrivateMessageConfigForm/PrivateMessageConfigFormBase.php b/src/Plugin/PrivateMessageConfigForm/PrivateMessageConfigFormBase.php
index 8b527411..51123c73 100644
--- a/src/Plugin/PrivateMessageConfigForm/PrivateMessageConfigFormBase.php
+++ b/src/Plugin/PrivateMessageConfigForm/PrivateMessageConfigFormBase.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\PrivateMessageConfigForm;
 
 use Drupal\Core\Config\ConfigFactoryInterface;
@@ -24,7 +26,7 @@ abstract class PrivateMessageConfigFormBase extends PluginBase implements Privat
   /**
    * {@inheritdoc}
    */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
     return new static(
       $configuration,
       $plugin_id,
@@ -36,14 +38,14 @@ abstract class PrivateMessageConfigFormBase extends PluginBase implements Privat
   /**
    * {@inheritdoc}
    */
-  public function getName() {
+  public function getName(): string {
     return $this->pluginDefinition['name'];
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getId() {
+  public function getId(): string {
     return $this->pluginDefinition['id'];
   }
 
diff --git a/src/Plugin/PrivateMessageConfigForm/PrivateMessageConfigFormPluginInterface.php b/src/Plugin/PrivateMessageConfigForm/PrivateMessageConfigFormPluginInterface.php
index 26d2e91a..2bb82716 100644
--- a/src/Plugin/PrivateMessageConfigForm/PrivateMessageConfigFormPluginInterface.php
+++ b/src/Plugin/PrivateMessageConfigForm/PrivateMessageConfigFormPluginInterface.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\PrivateMessageConfigForm;
 
 use Drupal\Component\Plugin\PluginInspectionInterface;
@@ -17,7 +19,7 @@ interface PrivateMessageConfigFormPluginInterface extends PluginInspectionInterf
    * @return string
    *   The name of the plugin.
    */
-  public function getName();
+  public function getName(): string;
 
   /**
    * Return the id of the crm tester plugin.
@@ -25,7 +27,7 @@ interface PrivateMessageConfigFormPluginInterface extends PluginInspectionInterf
    * @return string
    *   The id of the plugin.
    */
-  public function getId();
+  public function getId(): string;
 
   /**
    * Build the section of the form as it will appear on the settings page.
@@ -36,7 +38,7 @@ interface PrivateMessageConfigFormPluginInterface extends PluginInspectionInterf
    * @return array
    *   A render array containing the form elements this plugin provides.
    */
-  public function buildForm(FormStateInterface $formState);
+  public function buildForm(FormStateInterface $formState): array;
 
   /**
    * Validate this section of the form.
diff --git a/src/Plugin/RulesAction/SendPrivateMessage.php b/src/Plugin/RulesAction/SendPrivateMessage.php
index 81d2f120..d5a6accb 100644
--- a/src/Plugin/RulesAction/SendPrivateMessage.php
+++ b/src/Plugin/RulesAction/SendPrivateMessage.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\RulesAction;
 
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
@@ -51,7 +53,7 @@ class SendPrivateMessage extends RulesActionBase implements ContainerFactoryPlug
   /**
    * {@inheritdoc}
    */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
     return new static(
       $configuration,
       $plugin_id,
@@ -70,7 +72,7 @@ class SendPrivateMessage extends RulesActionBase implements ContainerFactoryPlug
    * @param string $message
    *   The text of the message.
    */
-  protected function doExecute(UserInterface $author, UserInterface $recipient, $message) {
+  protected function doExecute(UserInterface $author, UserInterface $recipient, string $message): void {
     $members = [$author, $recipient];
     // Create a thread if one does not exist.
     $private_message_thread = $this->privateMessageService->getThreadForMembers($members);
diff --git a/src/Plugin/Validation/Constraint/PrivateMessageThreadMemberConstraint.php b/src/Plugin/Validation/Constraint/PrivateMessageThreadMemberConstraint.php
index 569b5b48..753c6d5a 100644
--- a/src/Plugin/Validation/Constraint/PrivateMessageThreadMemberConstraint.php
+++ b/src/Plugin/Validation/Constraint/PrivateMessageThreadMemberConstraint.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\Validation\Constraint;
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
diff --git a/src/Plugin/Validation/Constraint/PrivateMessageThreadMemberConstraintValidator.php b/src/Plugin/Validation/Constraint/PrivateMessageThreadMemberConstraintValidator.php
index 2099fa51..83ccc8bf 100644
--- a/src/Plugin/Validation/Constraint/PrivateMessageThreadMemberConstraintValidator.php
+++ b/src/Plugin/Validation/Constraint/PrivateMessageThreadMemberConstraintValidator.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\Validation\Constraint;
 
 use Symfony\Component\Validator\Constraint;
@@ -16,7 +18,7 @@ class PrivateMessageThreadMemberConstraintValidator extends ConstraintValidator
   /**
    * {@inheritdoc}
    */
-  public function validate($items, Constraint $constraint) {
+  public function validate($items, Constraint $constraint): void {
     $users = $items->referencedEntities();
     foreach ($users as $user) {
       if (!$user->hasPermission('use private messaging system')) {
diff --git a/src/Plugin/Validation/Constraint/UniqueBanConstraint.php b/src/Plugin/Validation/Constraint/UniqueBanConstraint.php
index 717dca28..07c7672c 100644
--- a/src/Plugin/Validation/Constraint/UniqueBanConstraint.php
+++ b/src/Plugin/Validation/Constraint/UniqueBanConstraint.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\Validation\Constraint;
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
diff --git a/src/Plugin/Validation/Constraint/UniqueBanConstraintValidator.php b/src/Plugin/Validation/Constraint/UniqueBanConstraintValidator.php
index eeaf2d2b..70c8d841 100644
--- a/src/Plugin/Validation/Constraint/UniqueBanConstraintValidator.php
+++ b/src/Plugin/Validation/Constraint/UniqueBanConstraintValidator.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\Validation\Constraint;
 
 use Drupal\Core\DependencyInjection\AutowireTrait;
@@ -23,7 +25,7 @@ class UniqueBanConstraintValidator extends ConstraintValidator implements Contai
   /**
    * {@inheritdoc}
    */
-  public function validate($entity, Constraint $constraint) {
+  public function validate($entity, Constraint $constraint): void {
     assert($entity instanceof PrivateMessageBan);
 
     $storage = $this->entityTypeManager->getStorage('private_message_ban');
diff --git a/src/Plugin/views/field/PrivateMessageThreadHasNewMessage.php b/src/Plugin/views/field/PrivateMessageThreadHasNewMessage.php
index 0366e16f..b771adda 100644
--- a/src/Plugin/views/field/PrivateMessageThreadHasNewMessage.php
+++ b/src/Plugin/views/field/PrivateMessageThreadHasNewMessage.php
@@ -1,7 +1,10 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\views\field;
 
+use Drupal\Component\Render\MarkupInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\private_message\Service\PrivateMessageServiceInterface;
 use Drupal\views\Attribute\ViewsField;
@@ -30,7 +33,7 @@ class PrivateMessageThreadHasNewMessage extends FieldPluginBase {
   /**
    * {@inheritdoc}
    */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
     return new static(
       $configuration,
       $plugin_id,
@@ -43,14 +46,14 @@ class PrivateMessageThreadHasNewMessage extends FieldPluginBase {
   /**
    * {@inheritdoc}
    */
-  public function query() {
+  public function query(): void {
     // Disable query.
   }
 
   /**
    * {@inheritdoc}
    */
-  public function render(ResultRow $values) {
+  public function render(ResultRow $values): MarkupInterface {
     /** @var \Drupal\private_message\Entity\PrivateMessageThread $thread */
     $thread = $this->getEntity($values);
 
diff --git a/src/Plugin/views/field/PrivateMessageThreadMessagesCount.php b/src/Plugin/views/field/PrivateMessageThreadMessagesCount.php
index bbd4fbdc..8d5a6a42 100644
--- a/src/Plugin/views/field/PrivateMessageThreadMessagesCount.php
+++ b/src/Plugin/views/field/PrivateMessageThreadMessagesCount.php
@@ -28,7 +28,7 @@ class PrivateMessageThreadMessagesCount extends FieldPluginBase {
   /**
    * {@inheritdoc}
    */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
     return new static(
       $configuration,
       $plugin_id,
@@ -40,18 +40,18 @@ class PrivateMessageThreadMessagesCount extends FieldPluginBase {
   /**
    * {@inheritdoc}
    */
-  public function query() {
+  public function query(): void {
     // Leave empty to avoid a query on this field.
   }
 
   /**
    * {@inheritdoc}
    */
-  public function render(ResultRow $values) {
+  public function render(ResultRow $values): string {
     /** @var \Drupal\private_message\Entity\PrivateMessageThread $thread */
     $thread = $this->getEntity($values);
 
-    return count($thread->filterUserDeletedMessages($this->currentUser));
+    return (string) count($thread->filterUserDeletedMessages($this->currentUser));
   }
 
 }
diff --git a/src/Plugin/views/field/PrivateMessageThreadNewMessagesCount.php b/src/Plugin/views/field/PrivateMessageThreadNewMessagesCount.php
index 83fd3360..dfd8cb77 100644
--- a/src/Plugin/views/field/PrivateMessageThreadNewMessagesCount.php
+++ b/src/Plugin/views/field/PrivateMessageThreadNewMessagesCount.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\views\field;
 
 use Drupal\Core\Session\AccountInterface;
@@ -30,7 +32,7 @@ class PrivateMessageThreadNewMessagesCount extends FieldPluginBase {
   /**
    * {@inheritdoc}
    */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
     return new static(
       $configuration,
       $plugin_id,
@@ -43,19 +45,19 @@ class PrivateMessageThreadNewMessagesCount extends FieldPluginBase {
   /**
    * {@inheritdoc}
    */
-  public function query() {
+  public function query(): void {
     // Disable query.
   }
 
   /**
    * {@inheritdoc}
    */
-  public function render(ResultRow $values) {
+  public function render(ResultRow $values): string {
     /** @var \Drupal\private_message\Entity\PrivateMessageThread $thread */
     $thread = $this->getEntity($values);
 
     // @todo Optimize this, consider deletions and banned users.
-    return $this->privateMessageService->getThreadUnreadMessageCount($this->currentUser->id(), $thread->id());
+    return (string) $this->privateMessageService->getThreadUnreadMessageCount($this->currentUser->id(), $thread->id());
   }
 
 }
diff --git a/src/Plugin/views/filter/PrivateMessageThreadCleanHistory.php b/src/Plugin/views/filter/PrivateMessageThreadCleanHistory.php
index 3168e48a..f17b4d3c 100644
--- a/src/Plugin/views/filter/PrivateMessageThreadCleanHistory.php
+++ b/src/Plugin/views/filter/PrivateMessageThreadCleanHistory.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\views\filter;
 
 use Drupal\Core\Session\AccountInterface;
@@ -29,7 +31,7 @@ class PrivateMessageThreadCleanHistory extends FilterPluginBase {
   /**
    * {@inheritdoc}
    */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
     return new static(
       $configuration,
       $plugin_id,
@@ -44,7 +46,7 @@ class PrivateMessageThreadCleanHistory extends FilterPluginBase {
    *
    * No filtering takes place if the user doesn't select any options.
    */
-  public function query() {
+  public function query(): void {
     $current_user_id = $this->currentUser->id();
 
     $definition = [
@@ -68,12 +70,14 @@ class PrivateMessageThreadCleanHistory extends FilterPluginBase {
   /**
    * {@inheritdoc}
    */
-  public function adminSummary() {}
+  public function adminSummary(): \Stringable|string {
+    return '';
+  }
 
   /**
    * {@inheritdoc}
    */
-  public function canExpose() {
+  public function canExpose(): bool {
     return FALSE;
   }
 
diff --git a/src/Plugin/views/filter/PrivateMessageThreadIsUnread.php b/src/Plugin/views/filter/PrivateMessageThreadIsUnread.php
index dd7bfc32..dd5b841c 100644
--- a/src/Plugin/views/filter/PrivateMessageThreadIsUnread.php
+++ b/src/Plugin/views/filter/PrivateMessageThreadIsUnread.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\views\filter;
 
 use Drupal\Core\Session\AccountInterface;
@@ -29,7 +31,7 @@ class PrivateMessageThreadIsUnread extends FilterPluginBase {
   /**
    * {@inheritdoc}
    */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
     return new static(
       $configuration,
       $plugin_id,
@@ -42,7 +44,7 @@ class PrivateMessageThreadIsUnread extends FilterPluginBase {
   /**
    * Override the views query.
    */
-  public function query() {
+  public function query(): void {
     $current_user_id = $this->currentUser->id();
 
     $definition = [
@@ -66,12 +68,14 @@ class PrivateMessageThreadIsUnread extends FilterPluginBase {
   /**
    * {@inheritdoc}
    */
-  public function adminSummary() {}
+  public function adminSummary(): \Stringable|string {
+    return '';
+  }
 
   /**
    * {@inheritdoc}
    */
-  public function canExpose() {
+  public function canExpose(): bool {
     return FALSE;
   }
 
-- 
GitLab


From ef5f5b22db22fb50296e8d4e09238908d636445b Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Fri, 29 Nov 2024 12:04:18 +0200
Subject: [PATCH 18/30] Deprecate private_message.mapper service

---
 private_message.services.yml | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/private_message.services.yml b/private_message.services.yml
index a5e9c19b..ba9c4c53 100644
--- a/private_message.services.yml
+++ b/private_message.services.yml
@@ -4,11 +4,6 @@ services:
     autoconfigure: true
     autowire: true
 
-  private_message.mapper:
-    class: Drupal\private_message\Mapper\PrivateMessageMapper
-    deprecated: The "%service_id%" service is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. No replacement is provided. See https://www.drupal.org/node/3490530
-  Drupal\private_message\Mapper\PrivateMessageMapperInterface: '@private_message.mapper'
-
   private_message.service:
     class: Drupal\private_message\Service\PrivateMessageService
   Drupal\private_message\Service\PrivateMessageServiceInterface: '@private_message.service'
@@ -34,3 +29,7 @@ services:
     class: Drupal\private_message\PluginManager\PrivateMessageConfigFormManager
     parent: default_plugin_manager
   Drupal\private_message\PluginManager\PrivateMessageConfigFormManagerInterface: '@private_message.private_message_config_form_manager'
+
+  private_message.mapper:
+    class: Drupal\private_message\Mapper\PrivateMessageMapper
+    deprecated: The "%service_id%" service is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. No replacement is provided. See https://www.drupal.org/node/3490530
-- 
GitLab


From 897faddd7d69ce655fc243be14deda5d111ee62e Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Fri, 29 Nov 2024 16:25:29 +0200
Subject: [PATCH 19/30] Partial refactoring of private_message.service. More in
 #3489224.

---
 src/Controller/AjaxController.php             |  4 +-
 src/Service/PrivateMessageService.php         | 46 ++++++++++-----
 .../PrivateMessageServiceInterface.php        | 57 +++++++++----------
 3 files changed, 62 insertions(+), 45 deletions(-)

diff --git a/src/Controller/AjaxController.php b/src/Controller/AjaxController.php
index 3673ad5a..1e8a4e56 100644
--- a/src/Controller/AjaxController.php
+++ b/src/Controller/AjaxController.php
@@ -133,9 +133,9 @@ class AjaxController extends ControllerBase implements AjaxControllerInterface {
     $response = new AjaxResponse();
 
     $timestamp = $this->requestStack->getCurrentRequest()->get('timestamp');
-    $thread_count = $this->requestStack->getCurrentRequest()->get('count');
+    $thread_count = (int) $this->requestStack->getCurrentRequest()->get('count');
     if (is_numeric($timestamp)) {
-      $thread_info = $this->privateMessageService->getThreadsForUser($thread_count, $timestamp);
+      $thread_info = $this->privateMessageService->getThreadsForUser($thread_count, intval($timestamp));
       $has_next = FALSE;
       if (count($thread_info['threads'])) {
         $view_builder = $this->entityTypeManager()->getViewBuilder('private_message_thread');
diff --git a/src/Service/PrivateMessageService.php b/src/Service/PrivateMessageService.php
index d2f0b25a..7316e063 100644
--- a/src/Service/PrivateMessageService.php
+++ b/src/Service/PrivateMessageService.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Service;
 
 use Drupal\Component\Datetime\TimeInterface;
@@ -18,14 +20,26 @@ use Drupal\user\UserDataInterface;
 use Drupal\user\UserInterface;
 
 /**
- * The Private Message service for the private message module.
+ * The private message service for the private message module.
  *
- * @todo Replace direct calls to database with entity API calls and remove the
- *   $database class property in #3489224.
+ * @todo This service refactoring is postponed to #3489224. To be implemented:
+ *   - Replacement of direct calls to database with entity API calls and
+ *     removing the $database class property
+ *   - Strict typing with respect to BC.
  * @see https://www.drupal.org/project/private_message/issues/3489224
  */
 class PrivateMessageService implements PrivateMessageServiceInterface {
 
+  /**
+   * The machine name of the private message module.
+   */
+  private const MODULE_KEY = 'private_message';
+
+  /**
+   * The timestamp at which unread private messages were marked as read.
+   */
+  private const LAST_CHECK_KEY = 'last_notification_check_timestamp';
+
   public function __construct(
     protected readonly AccountProxyInterface $currentUser,
     protected readonly ConfigFactoryInterface $configFactory,
@@ -39,7 +53,7 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
   /**
    * {@inheritdoc}
    */
-  public function getThreadForMembers(array $members) {
+  public function getThreadForMembers(array $members): PrivateMessageThreadInterface {
     $thread_id = $this->getThreadIdForMembers($members);
 
     if ($thread_id) {
@@ -54,7 +68,7 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
   /**
    * {@inheritdoc}
    */
-  public function getFirstThreadForUser(UserInterface $user) {
+  public function getFirstThreadForUser(UserInterface $user): PrivateMessageThreadInterface|false {
     $thread_id = $this->getFirstThreadIdForUser($user);
     if ($thread_id) {
       return $this->entityTypeManager
@@ -68,7 +82,13 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
   /**
    * {@inheritdoc}
    */
-  public function getThreadsForUser($count, $timestamp = FALSE) {
+  public function getThreadsForUser(int $count, /* ?int */$timestamp = NULL): array {
+    if ($timestamp === FALSE) {
+      // @deprecated
+      @trigger_error('Passing FALSE to second argument of ' . __METHOD__ . '() is deprecated in private_message:4.0.0 and removed from private_message:5.0.0. Pass NULL instead. See https://www.drupal.org/node/3490530', E_USER_DEPRECATED);
+      $timestamp = NULL;
+    }
+
     $return = [
       'threads' => [],
       'next_exists' => FALSE,
@@ -96,7 +116,7 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
   /**
    * {@inheritdoc}
    */
-  public function getCountThreadsForUser() {
+  public function getCountThreadsForUser(): int {
     $user = $this->entityTypeManager
       ->getStorage('user')
       ->load($this->currentUser->id());
@@ -379,7 +399,7 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
    * @return int|false
    *   The thread ID, if a thread is found, or FALSE.
    */
-  protected function getThreadIdForMembers(array $members): int|false {
+  protected function getThreadIdForMembers(array $members) {
     $uids = array_map(fn(UserInterface $user) => (int) $user->id(), $members);
 
     // Select threads common for the given members.
@@ -419,7 +439,7 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
    *   The ID of the most recently updated thread where the user is a member, or
    *   FALSE if one doesn't exist.
    */
-  protected function getFirstThreadIdForUser(UserInterface $user): int|false {
+  protected function getFirstThreadIdForUser(UserInterface $user) {
     $bannedThreadsQuery = $this->getBannedThreads($user->id());
 
     $query = $this->database->select('private_message_threads', 'thread');
@@ -577,7 +597,7 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
    * @return int
    *   The number of threads updated since the given timestamp
    */
-  protected function getUnreadThreadCountHelper($uid, $lastCheckTimestamp): int {
+  protected function getUnreadThreadCountHelper($uid, $lastCheckTimestamp) {
     $bannedThreadsQuery = $this->getBannedThreads($uid);
 
     $query = $this->database->select('private_messages', 'message');
@@ -653,7 +673,7 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
    *   The private message thread ID of the thread to which the private message
    *   belongs.
    */
-  protected function getThreadIdFromMessage(PrivateMessageInterface $privateMessage): int {
+  protected function getThreadIdFromMessage(PrivateMessageInterface $privateMessage) {
     $query = $this->database->select('private_message_threads', 'thread');
     $query->fields('thread', ['id']);
     $query->join('private_message_thread__private_messages',
@@ -670,13 +690,13 @@ class PrivateMessageService implements PrivateMessageServiceInterface {
   /**
    * Returns query object of banned threads for the user.
    *
-   * @param int $user_id
+   * @param int|string $user_id
    *   The user id.
    *
    * @return \Drupal\Core\Database\Query\SelectInterface
    *   The select query object.
    */
-  protected function getBannedThreads(int $user_id): SelectInterface {
+  protected function getBannedThreads(int|string $user_id): SelectInterface {
     // Get the list of banned users for this user.
     $subquery = $this->database->select('private_message_ban', 'pmb');
     $subquery->addField('pmb', 'target');
diff --git a/src/Service/PrivateMessageServiceInterface.php b/src/Service/PrivateMessageServiceInterface.php
index f2a40a34..6aa63562 100644
--- a/src/Service/PrivateMessageServiceInterface.php
+++ b/src/Service/PrivateMessageServiceInterface.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Service;
 
 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
@@ -9,70 +11,65 @@ use Drupal\private_message\Entity\PrivateMessageThreadInterface;
 use Drupal\user\UserInterface;
 
 /**
- * The interface for the Private Message Service.
+ * The interface for the private message service.
+ *
+ * @todo This service refactoring is postponed to #3489224. To be implemented:
+ *   - Replacement of direct calls to database with entity API calls and
+ *     removing the $database class property
+ *   - Strict typing with respect to BC.
+ * @see https://www.drupal.org/project/private_message/issues/3489224
  */
 interface PrivateMessageServiceInterface {
 
-  /**
-   * The machine name of the private message module.
-   */
-  const MODULE_KEY = 'private_message';
-
-  /**
-   * The timestamp at which unread private messages were marked as read.
-   */
-  const LAST_CHECK_KEY = 'last_notification_check_timestamp';
-
   /**
    * Retrieves the private message thread for the given members.
    *
    * If no thread exists, one will be created.
    *
    * @param \Drupal\user\UserInterface[] $members
-   *   An array of User objects for whom the private message
-   *   thread should be retrieved.
+   *   List of users for whom the private message thread should be retrieved.
    *
-   * @return \Drupal\private_message\Entity\PrivateMessageThread
+   * @return \Drupal\private_message\Entity\PrivateMessageThreadInterface
    *   A private message thread that contains all members in the thread.
    */
-  public function getThreadForMembers(array $members);
+  public function getThreadForMembers(array $members): PrivateMessageThreadInterface;
 
   /**
-   * Get the most recently updated thread for the given user.
+   * Returns the most recently updated thread for the given user.
    *
    * @param \Drupal\user\UserInterface $user
    *   The user whose most recently updated thread should be retrieved.
+   *
+   * @return \Drupal\private_message\Entity\PrivateMessageThreadInterface|false
+   *   The most recently updated thread for the given user or FALSE.
    */
-  public function getFirstThreadForUser(UserInterface $user);
+  public function getFirstThreadForUser(UserInterface $user): PrivateMessageThreadInterface|false;
 
   /**
-   * Retrieve private message threads for a given user.
+   * Retrieves private message threads for a given user.
    *
    * @param int $count
    *   The number of threads to retrieve.
-   * @param int $timestamp
-   *   A timestamp relative to which only threads with an earlier timestamp
-   *   should be returned.
+   * @param int|null $timestamp
+   *   Only threads with an earlier timestamp should be returned.
    *
-   * @return array
+   * @return array{threads: array<int, PrivateMessageThreadInterface>, next_exists: bool}
    *   An array with two keys:
-   *   - threads: an array of
-   *     \Drupal\private_message\Entity\PrivateMessageThread
-   *   - next_exists: a boolean indicating whether any more private message
-   *     threads exist after the last one
+   *   - threads: Array of private message threads keyed by their ID.
+   *   - next_exists: Whether more threads exist after the last one.
    */
-  public function getThreadsForUser($count, $timestamp = FALSE);
+  public function getThreadsForUser(int $count, /* ?int */$timestamp = NULL): array;
 
   /**
-   * Retrieve the number of threads a user has.
+   * Retrieves the number of threads a user has.
    *
    * @return int
    *   The number of threads a user has.
    */
-  public function getCountThreadsForUser();
+  public function getCountThreadsForUser(): int;
 
   /**
-   * Retrieve a users private messages created after the given ID.
+   * Retrieves a users private messages created after the given ID.
    *
    * @param int $threadId
    *   The ID of the thread from which messages should be retrieved.
-- 
GitLab


From 11f287e6e473284fd60dfce54489a8172cba3e50 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Fri, 29 Nov 2024 17:00:36 +0200
Subject: [PATCH 20/30] Finalize services strict typing

---
 src/Service/PrivateMessageThreadManager.php   | 50 +++----------------
 .../PrivateMessageThreadManagerInterface.php  | 12 ++---
 src/Service/PrivateMessageUninstaller.php     |  2 +-
 3 files changed, 14 insertions(+), 50 deletions(-)

diff --git a/src/Service/PrivateMessageThreadManager.php b/src/Service/PrivateMessageThreadManager.php
index db29e7cd..74409d2e 100644
--- a/src/Service/PrivateMessageThreadManager.php
+++ b/src/Service/PrivateMessageThreadManager.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Service;
 
 use Drupal\private_message\Entity\PrivateMessageInterface;
@@ -10,21 +12,6 @@ use Drupal\private_message\Entity\PrivateMessageThreadInterface;
  */
 class PrivateMessageThreadManager implements PrivateMessageThreadManagerInterface {
 
-  /**
-   * The private message.
-   */
-  private ?PrivateMessageInterface $message;
-
-  /**
-   * The message recipients.
-   */
-  private array $recipients = [];
-
-  /**
-   * The private message thread.
-   */
-  private ?PrivateMessageThreadInterface $thread;
-
   public function __construct(
     protected readonly PrivateMessageServiceInterface $privateMessageService,
   ) {}
@@ -32,37 +19,14 @@ class PrivateMessageThreadManager implements PrivateMessageThreadManagerInterfac
   /**
    * {@inheritdoc}
    */
-  public function saveThread(PrivateMessageInterface $message, array $recipients = [], ?PrivateMessageThreadInterface $thread = NULL): void {
-    $this->message = $message;
-    $this->thread = $thread;
-    $this->recipients = $recipients;
-
-    $this->getThread()->addMessage();
-  }
-
-  /**
-   * If no thread is defined, load one from the thread members.
-   *
-   * @return $this
-   */
-  private function getThread(): PrivateMessageThreadManagerInterface {
-    if (is_null($this->thread)) {
-      $this->thread = $this->privateMessageService->getThreadForMembers($this->recipients);
+  public function saveThread(PrivateMessageInterface $message, array $members = [], ?PrivateMessageThreadInterface $thread = NULL): void {
+    if ($thread === NULL && $members) {
+      $thread = $this->privateMessageService->getThreadForMembers($members);
     }
-    return $this;
-  }
 
-  /**
-   * Add the new message to the thread.
-   *
-   * @return $this
-   */
-  private function addMessage(): PrivateMessageThreadManagerInterface {
-    if ($this->thread) {
-      $this->thread->addMessage($this->message);
-      $this->thread->save();
+    if ($thread instanceof PrivateMessageThreadInterface) {
+      $thread->addMessage($message)->save();
     }
-    return $this;
   }
 
 }
diff --git a/src/Service/PrivateMessageThreadManagerInterface.php b/src/Service/PrivateMessageThreadManagerInterface.php
index 07f7e720..a2c882bb 100644
--- a/src/Service/PrivateMessageThreadManagerInterface.php
+++ b/src/Service/PrivateMessageThreadManagerInterface.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Service;
 
 use Drupal\private_message\Entity\PrivateMessageInterface;
@@ -7,8 +9,6 @@ use Drupal\private_message\Entity\PrivateMessageThreadInterface;
 
 /**
  * Handles the generation/update of private messages, threads, and metadata.
- *
- * @package Drupal\private_message\Service
  */
 interface PrivateMessageThreadManagerInterface {
 
@@ -19,12 +19,12 @@ interface PrivateMessageThreadManagerInterface {
    *
    * @param \Drupal\private_message\Entity\PrivateMessageInterface $message
    *   The new message object.
-   * @param array $recipients
-   *   (optional) An array of message recipients. Defaults to an empty array.
+   * @param array $members
+   *   (optional) An array of thread members. Defaults to an empty array.
    * @param \Drupal\private_message\Entity\PrivateMessageThreadInterface|null $thread
    *   (optional) The private message thread. If NULL, one will be loaded
-   *   using the recipients array.
+   *   using the members array.
    */
-  public function saveThread(PrivateMessageInterface $message, array $recipients = [], ?PrivateMessageThreadInterface $thread = NULL);
+  public function saveThread(PrivateMessageInterface $message, array $members = [], ?PrivateMessageThreadInterface $thread = NULL);
 
 }
diff --git a/src/Service/PrivateMessageUninstaller.php b/src/Service/PrivateMessageUninstaller.php
index cd104359..2b4d1c49 100644
--- a/src/Service/PrivateMessageUninstaller.php
+++ b/src/Service/PrivateMessageUninstaller.php
@@ -110,7 +110,7 @@ class PrivateMessageUninstaller implements PrivateMessageUninstallerInterface {
    *   Thread id.
    */
   public static function deleteThread(int $threadId): void {
-    /** @var \Drupal\private_message\Entity\PrivateMessageThreadInterface $thread */
+    /** @var \Drupal\private_message\Entity\PrivateMessageThreadInterface|null $thread */
     $thread = \Drupal::entityTypeManager()
       ->getStorage('private_message_thread')
       ->load($threadId);
-- 
GitLab


From 97f112846a568b8cafadea9bd8fb456f9388ff73 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Fri, 29 Nov 2024 17:01:03 +0200
Subject: [PATCH 21/30] Strict type private_message.tokens.inc

---
 private_message.tokens.inc | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/private_message.tokens.inc b/private_message.tokens.inc
index 429f4b17..9bc047b6 100644
--- a/private_message.tokens.inc
+++ b/private_message.tokens.inc
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 /**
  * @file
  * Provides tokens for the Private Message module.
@@ -14,8 +16,7 @@ use Drupal\user\Entity\User;
 /**
  * Implements hook_token_info().
  */
-function private_message_token_info() {
-
+function private_message_token_info(): array {
   // Defined the private message token type.
   $private_message_type = [
     'name' => t('Private Messages'),
@@ -89,7 +90,7 @@ function private_message_token_info() {
 /**
  * Implements hook_tokens().
  */
-function private_message_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
+function private_message_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata): array {
   $replacements = [];
 
   $token_service = \Drupal::token();
-- 
GitLab


From 4a9afef28c6ad5c899014dbc5a2cf4aaa614cc63 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Fri, 29 Nov 2024 17:33:05 +0200
Subject: [PATCH 22/30] Procedural code strict typing

---
 .../private_message_notify.api.php            |   2 +
 .../PrivateMessageNotifierInterface.php       |   2 +
 private_message.api.php                       |   2 +
 private_message.install                       | 103 +++++++++---------
 private_message.module                        |   2 +
 private_message.theme.inc                     |   4 +-
 .../PrivateMessageThreadMessagesCount.php     |   3 +-
 7 files changed, 64 insertions(+), 54 deletions(-)

diff --git a/modules/private_message_notify/private_message_notify.api.php b/modules/private_message_notify/private_message_notify.api.php
index 2a57e695..7e39ca55 100644
--- a/modules/private_message_notify/private_message_notify.api.php
+++ b/modules/private_message_notify/private_message_notify.api.php
@@ -5,6 +5,8 @@
  * Hook documentation for Private Message Notify module hooks.
  */
 
+declare(strict_types=1);
+
 use Drupal\private_message\Entity\PrivateMessageInterface;
 use Drupal\private_message\Entity\PrivateMessageThreadInterface;
 
diff --git a/modules/private_message_notify/src/Service/PrivateMessageNotifierInterface.php b/modules/private_message_notify/src/Service/PrivateMessageNotifierInterface.php
index e43c62af..eafcd09d 100644
--- a/modules/private_message_notify/src/Service/PrivateMessageNotifierInterface.php
+++ b/modules/private_message_notify/src/Service/PrivateMessageNotifierInterface.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message_notify\Service;
 
 use Drupal\private_message\Entity\PrivateMessageInterface;
diff --git a/private_message.api.php b/private_message.api.php
index 383a616f..c4321b97 100644
--- a/private_message.api.php
+++ b/private_message.api.php
@@ -5,6 +5,8 @@
  * Hook documentation for Private Message module hooks.
  */
 
+declare(strict_types=1);
+
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\private_message\Entity\PrivateMessageInterface;
 use Drupal\private_message\Entity\PrivateMessageThreadInterface;
diff --git a/private_message.install b/private_message.install
index cb05f80e..c84a9875 100644
--- a/private_message.install
+++ b/private_message.install
@@ -5,6 +5,8 @@
  * Holds install and update hooks for the Private Message module.
  */
 
+declare(strict_types=1);
+
 use Drupal\Core\Database\IntegrityConstraintViolationException;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\private_message\Model\BlockType;
@@ -12,7 +14,7 @@ use Drupal\private_message\Model\BlockType;
 /**
  * Implements hook_install().
  */
-function private_message_install() {
+function private_message_install(): void {
   $messenger = \Drupal::messenger();
   $messenger->addStatus(t('Make sure you granted "use private messaging system" and "access user profiles" permissions for roles you want to provide access to use private messages.'));
   $messenger->addStatus(t('Enable "Private Message Actions" and "Private Message Inbox" block to have simple private message UI from the box.'));
@@ -21,7 +23,7 @@ function private_message_install() {
 /**
  * Implements hook_uninstall().
  */
-function private_message_uninstall() {
+function private_message_uninstall(): void {
   \Drupal::configFactory()->getEditable('core.entity_view_display.user.user.private_message_author')->delete();
   \Drupal::configFactory()->getEditable('core.entity_view_mode.user.private_message_author')->delete();
   \Drupal::configFactory()->getEditable('message.template.private_message_notification')->delete();
@@ -31,41 +33,10 @@ function private_message_uninstall() {
   \Drupal::configFactory()->getEditable('core.entity_view_display.message.private_message_notification.default')->delete();
 }
 
-/**
- * Implements hook_update_n().
- */
-function private_message_update_8001() {
-  $config_factory = \Drupal::configFactory();
-
-  $config_factory->getEditable('private_message.settings')
-    ->set('enable_email_notifications', TRUE)
-    ->set('send_by_default', TRUE)
-    ->save(TRUE);
-
-  $message_notification_mail_map = [
-    'subject' => 'Private message at [site:name]',
-    'body' => "[user:display-name],\n\nYou have received a private message at [site:name] from [private_message:author_name]\n\nThe message is as follows:\n\n[private_message:message]\n\nYou can view the entire thread and reply to this message at:\n\n[private_message_thread:url]\n\n\nThank you,\n\n--  [site:name]",
-  ];
-
-  $config_factory->getEditable('private_message.mail')
-    ->set('message_notification', $message_notification_mail_map)
-    ->save(TRUE);
-}
-
-/**
- * Add the create private message label.
- */
-function private_message_update_8002() {
-  $config_factory = \Drupal::configFactory();
-  $config_factory->getEditable('private_message.settings')
-    ->set('create_message_label', 'Create Private Message')
-    ->save(TRUE);
-}
-
 /**
  * Implements hook_schema().
  */
-function private_message_schema() {
+function private_message_schema(): array {
   $schema['pm_thread_history'] = [
     'description' => 'A record of which {users} have read which {node}s.',
     'fields' => [
@@ -104,10 +75,41 @@ function private_message_schema() {
   return $schema;
 }
 
+/**
+ * Implements hook_update_n().
+ */
+function private_message_update_8001(): void {
+  $config_factory = \Drupal::configFactory();
+
+  $config_factory->getEditable('private_message.settings')
+    ->set('enable_email_notifications', TRUE)
+    ->set('send_by_default', TRUE)
+    ->save(TRUE);
+
+  $message_notification_mail_map = [
+    'subject' => 'Private message at [site:name]',
+    'body' => "[user:display-name],\n\nYou have received a private message at [site:name] from [private_message:author_name]\n\nThe message is as follows:\n\n[private_message:message]\n\nYou can view the entire thread and reply to this message at:\n\n[private_message_thread:url]\n\n\nThank you,\n\n--  [site:name]",
+  ];
+
+  $config_factory->getEditable('private_message.mail')
+    ->set('message_notification', $message_notification_mail_map)
+    ->save(TRUE);
+}
+
 /**
  * Add the create private message label.
  */
-function private_message_update_8003() {
+function private_message_update_8002(): void {
+  $config_factory = \Drupal::configFactory();
+  $config_factory->getEditable('private_message.settings')
+    ->set('create_message_label', 'Create Private Message')
+    ->save(TRUE);
+}
+
+/**
+ * Add the create private message label.
+ */
+function private_message_update_8003(): void {
   $config_factory = \Drupal::configFactory();
   $config_factory->getEditable('private_message.settings')
     ->set('create_message_label', 'Create Private Message')
@@ -117,7 +119,7 @@ function private_message_update_8003() {
 /**
  * Install the module schema.
  */
-function private_message_update_8004() {
+function private_message_update_8004(): void {
   $database = \Drupal::database();
 
   // Create database table.
@@ -162,7 +164,7 @@ function private_message_update_8004() {
 /**
  * Migrate the records into a new table.
  */
-function private_message_update_8005(&$sandbox) {
+function private_message_update_8005(?array &$sandbox = NULL): void {
   // Store last processed thread ID, so the sites with a huge amount of threads
   // will have at least some chances to complete this update in a few runs.
   $last_processed = \Drupal::state()->get('scalable_bridge_last', 0);
@@ -259,7 +261,7 @@ function private_message_update_8005(&$sandbox) {
 /**
  * Drop the old entity types and field definitions.
  */
-function private_message_update_8006(&$sandbox) {
+function private_message_update_8006(?array &$sandbox = NULL): void {
   $entity_update_manager = \Drupal::entityDefinitionUpdateManager();
   foreach (['pm_thread_access_time', 'pm_thread_delete_time'] as $entity_type_id) {
     if ($entity_type = $entity_update_manager->getEntityType($entity_type_id)) {
@@ -276,7 +278,7 @@ function private_message_update_8006(&$sandbox) {
 /**
  * Enable notifications submodule.
  */
-function private_message_update_8007() {
+function private_message_update_8007(): void {
   // Delete the configs that will be migrated to private_message_notify.
   // Only delete configurations if private_message_notify is not installed
   // already.
@@ -361,7 +363,7 @@ function private_message_update_8008() {
 /**
  * Skip update because of unnecessary.
  */
-function private_message_update_8009() {
+function private_message_update_8009(): void {
   // Leave this hook update empty because it already passed who applied patch
   // from issue https://www.drupal.org/project/private_message/issues/3265901
 }
@@ -369,7 +371,7 @@ function private_message_update_8009() {
 /**
  * Skip update because of unnecessary.
  */
-function private_message_update_8010() {
+function private_message_update_8010(): void {
   // Leave this hook update empty because it already passed who applied patch
   // from issue https://www.drupal.org/project/private_message/issues/3265901
 }
@@ -377,22 +379,19 @@ function private_message_update_8010() {
 /**
  * Install the private_message_ban entity type.
  */
-function private_message_update_8011() {
-
-  if (!\Drupal::database()->schema()->tableExists('private_message_ban')) {
-    \Drupal::entityTypeManager()->clearCachedDefinitions();
-    \Drupal::entityDefinitionUpdateManager()->installEntityType(\Drupal::entityTypeManager()->getDefinition('private_message_ban'));
-  }
-  else {
+function private_message_update_8011(): string {
+  if (\Drupal::database()->schema()->tableExists('private_message_ban')) {
     return 'Private Message Ban entity already exists';
   }
-
+  \Drupal::entityTypeManager()->clearCachedDefinitions();
+  \Drupal::entityDefinitionUpdateManager()->installEntityType(\Drupal::entityTypeManager()->getDefinition('private_message_ban'));
+  return 'Installed Private Message Ban entity';
 }
 
 /**
  * Sets default values for the block functionality.
  */
-function private_message_update_8012() {
+function private_message_update_8012(): void {
   \Drupal::configFactory()->getEditable('private_message.settings')
     ->set('ban_mode', BlockType::Passive->value)
     ->set('ban_message', 'User is unable to receive your message')
@@ -404,7 +403,7 @@ function private_message_update_8012() {
 /**
  * Install the `subject` field to 'private_message_thread' entity.
  */
-function private_message_update_8013() {
+function private_message_update_8013(): void {
   $storage_definition = BaseFieldDefinition::create('string')
     ->setLabel(t('Subject'))
     ->setSetting('max_length', 64)
@@ -422,7 +421,7 @@ function private_message_update_8013() {
 /**
  * Show input formats functionality.
  */
-function private_message_update_8014() {
+function private_message_update_8014(): void {
   $config = \Drupal::configFactory()
     ->getEditable('private_message.settings');
   $rows = $config->getRawData();
diff --git a/private_message.module b/private_message.module
index ff8979ac..26f2452c 100644
--- a/private_message.module
+++ b/private_message.module
@@ -5,6 +5,8 @@
  * Contains hooks for the private message module.
  */
 
+declare(strict_types=1);
+
 use Drupal\Component\Render\MarkupInterface;
 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
 use Drupal\Core\Entity\EntityInterface;
diff --git a/private_message.theme.inc b/private_message.theme.inc
index c9d67214..7cd903f1 100644
--- a/private_message.theme.inc
+++ b/private_message.theme.inc
@@ -5,13 +5,15 @@
  * Contains preprocess functions for the private message module.
  */
 
+declare(strict_types=1);
+
 use Drupal\Core\Link;
 use Drupal\Core\Url;
 
 /**
  * Implements hook_preprocess_private_message_notification_block().
  */
-function template_preprocess_private_message_notification_block(&$vars) {
+function template_preprocess_private_message_notification_block(array &$vars): void {
   $vars['notification_image_path'] = base_path() . \Drupal::service('extension.list.module')->getPath('private_message') . '/images/private-message-notification-icon.png';
 
   switch ($vars['count_method']) {
diff --git a/src/Plugin/views/field/PrivateMessageThreadMessagesCount.php b/src/Plugin/views/field/PrivateMessageThreadMessagesCount.php
index 8d5a6a42..e9d9dc80 100644
--- a/src/Plugin/views/field/PrivateMessageThreadMessagesCount.php
+++ b/src/Plugin/views/field/PrivateMessageThreadMessagesCount.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Drupal\private_message\Plugin\views\field;
 
 use Drupal\Core\Session\AccountInterface;
@@ -50,7 +52,6 @@ class PrivateMessageThreadMessagesCount extends FieldPluginBase {
   public function render(ResultRow $values): string {
     /** @var \Drupal\private_message\Entity\PrivateMessageThread $thread */
     $thread = $this->getEntity($values);
-
     return (string) count($thread->filterUserDeletedMessages($this->currentUser));
   }
 
-- 
GitLab


From 392bd986c51e404cad13a563c572580a420e2f59 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Fri, 29 Nov 2024 17:33:27 +0200
Subject: [PATCH 23/30] Strict type private_message.tokens.inc

---
 private_message.tokens.inc | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/private_message.tokens.inc b/private_message.tokens.inc
index 9bc047b6..7c5dec4b 100644
--- a/private_message.tokens.inc
+++ b/private_message.tokens.inc
@@ -1,12 +1,12 @@
 <?php
 
-declare(strict_types=1);
-
 /**
  * @file
  * Provides tokens for the Private Message module.
  */
 
+declare(strict_types=1);
+
 use Drupal\Core\Datetime\Entity\DateFormat;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Render\BubbleableMetadata;
-- 
GitLab


From 059d08eb4ecba8a55c42a0098de42c27d09d47d6 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Fri, 29 Nov 2024 17:35:05 +0200
Subject: [PATCH 24/30] Enforce declare(strict_types=1)

---
 .gitignore     |  1 -
 phpcs.xml.dist | 14 ++++++++++++++
 2 files changed, 14 insertions(+), 1 deletion(-)
 create mode 100644 phpcs.xml.dist

diff --git a/.gitignore b/.gitignore
index 1ac1b8d8..2b9dc5aa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,6 @@
 /.gitattributes
 /.prettierignore
 /.prettierrc.json
-/phpcs.xml.dist
 /phpstan-baseline.neon
 /phpstan.neon
 /vendor/
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
new file mode 100644
index 00000000..e7717fd5
--- /dev/null
+++ b/phpcs.xml.dist
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ruleset name="private_message">
+  <description>PHP CodeSniffer configuration for Private Message module.</description>
+  <rule ref="vendor/drupal/coder/coder_sniffer/Drupal/ruleset.xml"/>
+  <arg name="extensions" value="php,inc,module,install,info,test,profile,theme"/>
+
+  <!-- Strict typing & type hinting rules -->
+  <rule ref="SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing">
+    <severity>5</severity>
+    <!-- TODO: Remove these two exclusions in private_message:5.0.0 -->
+    <exclude-pattern>src/Mapper/PrivateMessageMapper.php</exclude-pattern>
+    <exclude-pattern>src/Mapper/PrivateMessageMapperInterface.php</exclude-pattern>
+  </rule>
+</ruleset>
-- 
GitLab


From de0c054147243389a85f75be0e66b2c5ecbe28d7 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Fri, 29 Nov 2024 17:47:37 +0200
Subject: [PATCH 25/30] Fine tunning

---
 src/Entity/PrivateMessage.php | 5 -----
 src/Form/ConfigForm.php       | 8 ++++----
 2 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/src/Entity/PrivateMessage.php b/src/Entity/PrivateMessage.php
index 1ccb2e68..0209eb0e 100644
--- a/src/Entity/PrivateMessage.php
+++ b/src/Entity/PrivateMessage.php
@@ -52,11 +52,6 @@ class PrivateMessage extends ContentEntityBase implements PrivateMessageInterfac
 
   /**
    * {@inheritdoc}
-   *
-   * @deprecated in private_message:4.0.0 and is removed from
-   *   private_message:5.0.0. Instead, access the 'message' field.
-   *
-   * @see https://www.drupal.org/node/3490530
    */
   public function getMessage() {
     @trigger_error(__METHOD__ . "() is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. Instead, access the 'message' field. See https://www.drupal.org/node/3490530", E_USER_DEPRECATED);
diff --git a/src/Form/ConfigForm.php b/src/Form/ConfigForm.php
index 59478cbe..548d2382 100644
--- a/src/Form/ConfigForm.php
+++ b/src/Form/ConfigForm.php
@@ -23,8 +23,8 @@ class ConfigForm extends ConfigFormBase {
    * Blocking type: passive.
    *
    * @deprecated in private_message:4.0.0 and is removed from
-   * private_message:5.0.0. Use \Drupal\private_message\Model\BlockType::Passive
-   * instead.
+   *   private_message:5.0.0. Instead, use
+   *   \Drupal\private_message\Model\BlockType::Passive.
    *
    * @see https://www.drupal.org/node/3490530
    */
@@ -34,8 +34,8 @@ class ConfigForm extends ConfigFormBase {
    * Blocking type: active.
    *
    * @deprecated in private_message:4.0.0 and is removed from
-   * private_message:5.0.0. Use \Drupal\private_message\Model\BlockType::Active
-   * instead.
+   *   private_message:5.0.0. Instead, use
+   *   \Drupal\private_message\Model\BlockType::Active.
    *
    * @see https://www.drupal.org/node/3490530
    */
-- 
GitLab


From 4534ac0f2fcf1e95fb88565145245663a5f879ce Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Mon, 2 Dec 2024 22:46:02 +0200
Subject: [PATCH 26/30] Deprecate
 PrivateMessageNotifier::getNotificationRecipients()

---
 .../src/Service/PrivateMessageNotifier.php    | 56 +++++++++++--------
 1 file changed, 34 insertions(+), 22 deletions(-)

diff --git a/modules/private_message_notify/src/Service/PrivateMessageNotifier.php b/modules/private_message_notify/src/Service/PrivateMessageNotifier.php
index cde6646b..fc052ea5 100644
--- a/modules/private_message_notify/src/Service/PrivateMessageNotifier.php
+++ b/modules/private_message_notify/src/Service/PrivateMessageNotifier.php
@@ -41,7 +41,7 @@ class PrivateMessageNotifier implements PrivateMessageNotifierInterface {
    * {@inheritdoc}
    */
   public function notify(PrivateMessageInterface $message, PrivateMessageThreadInterface $thread): void {
-    $members = $this->getNotificationRecipients($message, $thread);
+    $members = $this->getRecipients($message, $thread);
 
     foreach ($members as $member) {
       // Skip the current user and any member without a valid email.
@@ -68,14 +68,12 @@ class PrivateMessageNotifier implements PrivateMessageNotifierInterface {
       // Create and send the notification.
       $notification = $this->entityTypeManager
         ->getStorage('message')
-        ->create(
-                [
-                  'template' => 'private_message_notification',
-                  'uid' => $member->id(),
-                ]
-            );
-      $notification->set('field_message_private_message', $message);
-      $notification->set('field_message_pm_thread', $thread);
+        ->create([
+          'template' => 'private_message_notification',
+          'uid' => $member->id(),
+          'field_message_private_message' => $message,
+          'field_message_pm_thread' => $thread,
+        ]);
       $notification->setLanguage($member->getPreferredLangcode());
       $notification->save();
 
@@ -96,9 +94,9 @@ class PrivateMessageNotifier implements PrivateMessageNotifierInterface {
    *   The private message thread.
    *
    * @return bool
-   *   A boolean indicating whether or not the message should be sent.
+   *   A boolean indicating whether the message should be sent.
    */
-  private function shouldSend(AccountInterface $recipient, PrivateMessageInterface $message, PrivateMessageThreadInterface $thread) {
+  private function shouldSend(AccountInterface $recipient, PrivateMessageInterface $message, PrivateMessageThreadInterface $thread): bool {
     // Don't notify the user by default.
     $notify = FALSE;
 
@@ -158,24 +156,21 @@ class PrivateMessageNotifier implements PrivateMessageNotifierInterface {
   }
 
   /**
-   * The users to receive notifications.
+   * Returns the list of recipients as user accounts.
    *
    * @return \Drupal\Core\Session\AccountInterface[]
-   *   An array of Account objects of the thread members who are to receive
-   *   the notification.
+   *   Array of thread members user entities receiving the notification.
    */
-  public function getNotificationRecipients(PrivateMessageInterface $message, PrivateMessageThreadInterface $thread) {
+  protected function getRecipients(PrivateMessageInterface $message, PrivateMessageThreadInterface $thread): array {
     $recipients = $thread->getMembers();
     $exclude = [];
 
     // Allow other modules to alter notification recipients.
-    $this->moduleHandler->invokeAll(
-      'private_message_notify_exclude', [
-        $message,
-        $thread,
-        &$exclude,
-      ]
-    );
+    $this->moduleHandler->invokeAll('private_message_notify_exclude', [
+      $message,
+      $thread,
+      &$exclude,
+    ]);
 
     if (empty($exclude)) {
       return $recipients;
@@ -190,4 +185,21 @@ class PrivateMessageNotifier implements PrivateMessageNotifierInterface {
     );
   }
 
+  /**
+   * The users to receive notifications.
+   *
+   * @return \Drupal\Core\Session\AccountInterface[]
+   *   An array of Account objects of the thread members who are to receive
+   *   the notification.
+   *
+   * @deprecated in private_message:4.0.0 and is removed from
+   *   private_message:5.0.0. Instead, use self ::getRecipients()
+   *
+   * @see https://www.drupal.org/node/3490530
+   */
+  public function getNotificationRecipients(PrivateMessageInterface $message, PrivateMessageThreadInterface $thread) {
+    @trigger_error(__METHOD__ . '() is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. Instead, use self ::getRecipients(). See https://www.drupal.org/node/3490530', E_USER_DEPRECATED);
+    return $this->getRecipients($message, $thread);
+  }
+
 }
-- 
GitLab


From 8f98c8ce4cbd8dc44d594919a2c7eda37386aaca Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Mon, 2 Dec 2024 23:06:57 +0200
Subject: [PATCH 27/30] Create PrivateMessageControllerInterface::configPage()

---
 src/Controller/PrivateMessageControllerInterface.php | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/Controller/PrivateMessageControllerInterface.php b/src/Controller/PrivateMessageControllerInterface.php
index d1e5ce1a..b1e8b39d 100644
--- a/src/Controller/PrivateMessageControllerInterface.php
+++ b/src/Controller/PrivateMessageControllerInterface.php
@@ -34,6 +34,14 @@ interface PrivateMessageControllerInterface {
   public function pmThreadSettingsPage(): array;
 
   /**
+   * Provides a controller for the private_message.admin_config.config route.
+   *
+   * @return array
+   *   Render array.
+   */
+  public function configPage(): array;
+
+    /**
    * The page for preparing to uninstall the module.
    *
    * @return array
-- 
GitLab


From edf91f4bea3356006fbbf5932d60960051d6bad7 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Mon, 2 Dec 2024 23:59:11 +0200
Subject: [PATCH 28/30] Use #config_target

---
 config/schema/private_message.schema.yml |  4 ++
 src/Form/ConfigForm.php                  | 47 ++++++++----------------
 2 files changed, 20 insertions(+), 31 deletions(-)

diff --git a/config/schema/private_message.schema.yml b/config/schema/private_message.schema.yml
index a5a8680c..b6dd17df 100644
--- a/config/schema/private_message.schema.yml
+++ b/config/schema/private_message.schema.yml
@@ -26,6 +26,10 @@ private_message.settings:
     ban_mode:
       type: string
       label: 'The blocking mode.'
+      constraints:
+        Choice:
+          - passive
+          - active
     ban_message:
       type: string
       label: 'The message to show to the user when they are blocked.'
diff --git a/src/Form/ConfigForm.php b/src/Form/ConfigForm.php
index 548d2382..a8ecdcb4 100644
--- a/src/Form/ConfigForm.php
+++ b/src/Form/ConfigForm.php
@@ -8,6 +8,7 @@ use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Config\TypedConfigManagerInterface;
 use Drupal\Core\DependencyInjection\AutowireTrait;
 use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\ConfigTarget;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\private_message\Model\BlockType;
 use Drupal\private_message\PluginManager\PrivateMessageConfigFormManagerInterface;
@@ -77,7 +78,7 @@ class ConfigForm extends ConfigFormBase {
     $form['pm_core']['notifications']['enable_notifications'] = [
       '#type' => 'checkbox',
       '#title' => $this->t('Enable notifications'),
-      '#default_value' => $config->get('enable_notifications'),
+      '#config_target' => new ConfigTarget('private_message.settings', 'enable_notifications', NULL, fn($value): bool => boolval($value)),
     ];
 
     $form['pm_core']['notifications']['notify_by_default'] = [
@@ -87,7 +88,7 @@ class ConfigForm extends ConfigFormBase {
         $this->t('Do not send notifications (users can opt-in)'),
         $this->t('Send notifications (users can opt-out)'),
       ],
-      '#default_value' => (int) $config->get('notify_by_default'),
+      '#config_target' => new ConfigTarget('private_message.settings', 'notify_by_default', NULL, fn($value): bool => boolval($value)),
       '#states' => [
         'visible' => [
           ':input[name="enable_notifications"]' => ['checked' => TRUE],
@@ -102,7 +103,7 @@ class ConfigForm extends ConfigFormBase {
         'yes' => $this->t('For every private message'),
         'no' => $this->t('Only when the user is not viewing the thread'),
       ],
-      '#default_value' => $config->get('notify_when_using'),
+      '#config_target' => 'private_message.settings:notify_when_using',
       '#description' => $this->t("Whether or not notifications should be sent when the user is viewing a given thread. Users will be able to override this value on their profile settings page."),
       '#states' => [
         'visible' => [
@@ -114,7 +115,7 @@ class ConfigForm extends ConfigFormBase {
     $form['pm_core']['notifications']['number_of_seconds_considered_away'] = [
       '#type' => 'number',
       '#title' => $this->t('The number of seconds after which a user should be considered as not viewing a thread'),
-      '#default_value' => $config->get('number_of_seconds_considered_away'),
+      '#config_target' => new ConfigTarget('private_message.settings', 'number_of_seconds_considered_away', NULL, fn($value): int => intval($value)),
       '#description' => $this->t('When users have a private message thread open, calls to the server update the last time they have accessed the thread. This setting determines how many seconds after they have closed the thread, they should be considered as not accessing the thread anymore. Users will be able to override this value on their profile settings page.'),
       '#states' => [
         'visible' => [
@@ -128,7 +129,7 @@ class ConfigForm extends ConfigFormBase {
       '#type' => 'checkbox',
       '#title' => $this->t('Hide recipient field when recipient is in the URL'),
       '#description' => $this->t('Links can be created to the private message page, passing the recipient in the URL. If this box is checked, the recipient field will be hidden when the recipient is passed in the URL.'),
-      '#default_value' => (int) $config->get('hide_recipient_field_when_prefilled'),
+      '#config_target' => new ConfigTarget('private_message.settings', 'hide_recipient_field_when_prefilled', NULL, fn($value): bool => boolval($value)),
     ];
 
     $form['pm_core']['autofocus_enable'] = [
@@ -136,6 +137,7 @@ class ConfigForm extends ConfigFormBase {
       '#title' => $this->t('Enable autofocus'),
       '#description' => $this->t('This option allows you to put the autofocus in the message textarea.'),
       '#default_value' => (int) $config->get('autofocus_enable'),
+      '#config_target' => new ConfigTarget('private_message.settings', 'autofocus_enable', NULL, fn($value): bool => boolval($value)),
     ];
 
     $form['pm_core']['keys_send'] = [
@@ -147,14 +149,14 @@ class ConfigForm extends ConfigFormBase {
           '@key-list' => 'https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values',
           '@keycode-list' => 'https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode',
         ]),
-      '#default_value' => $config->get('keys_send'),
+      '#config_target' => 'private_message.settings:keys_send',
     ];
 
     $form['pm_core']['remove_css'] = [
       '#type' => 'checkbox',
       '#title' => $this->t('Remove the default CSS of the module'),
       '#description' => $this->t('This option can break the features of the module and it is only for developers who want to override the styles more easily.'),
-      '#default_value' => (int) $config->get('remove_css'),
+      '#config_target' => new ConfigTarget('private_message.settings', 'remove_css', NULL, fn($value): bool => boolval($value)),
     ];
 
     $form['pm_labels'] = [
@@ -166,13 +168,13 @@ class ConfigForm extends ConfigFormBase {
     $form['pm_labels']['create_message_label'] = [
       '#type' => 'textfield',
       '#title' => $this->t("Text To Create Private Message"),
-      '#default_value' => $config->get('create_message_label'),
+      '#config_target' => 'private_message.settings:create_message_label',
     ];
 
     $form['pm_labels']['save_message_label'] = [
       '#type' => 'textfield',
       '#title' => $this->t("Text to submit a new message"),
-      '#default_value' => $config->get('save_message_label'),
+      '#config_target' => 'private_message.settings:save_message_label',
       '#description' => $this->t('The label of the button to send a new message.'),
     ];
 
@@ -185,7 +187,7 @@ class ConfigForm extends ConfigFormBase {
     $form['pm_block']['ban_mode'] = [
       '#type' => 'radios',
       '#title' => $this->t("Blocking mode"),
-      '#default_value' => $config->get('ban_mode') ?: BlockType::Passive->value,
+      '#config_target' => 'private_message.settings:ban_mode',
       '#options' => BlockType::asOptions(),
       BlockType::Passive->value => [
         '#description' => $this->t('Blocked members do not know they are blocked and can message the user that blocked them. The user who blocked them will not see the message.'),
@@ -198,25 +200,26 @@ class ConfigForm extends ConfigFormBase {
     $form['pm_block']['ban_label'] = [
       '#type' => 'textfield',
       '#title' => $this->t("Button label to ban a user"),
-      '#default_value' => $config->get('ban_label'),
+      '#config_target' => 'private_message.settings:ban_label',
     ];
 
     $form['pm_block']['unban_label'] = [
       '#type' => 'textfield',
       '#title' => $this->t("Button label to unban a user"),
-      '#default_value' => $config->get('unban_label'),
+      '#config_target' => 'private_message.settings:unban_label',
     ];
 
     $form['pm_block']['ban_page_label'] = [
       '#type' => 'textfield',
       '#title' => $this->t("Text to go to the ban page"),
       '#default_value' => $config->get('ban_page_label'),
+      '#config_target' => 'private_message.settings:ban_page_label',
     ];
 
     $form['pm_block']['ban_message'] = [
       '#type' => 'textfield',
       '#title' => $this->t("Text to show when a blocked user tries to send a message."),
-      '#default_value' => $config->get('ban_message'),
+      '#config_target' => 'private_message.settings:ban_message',
     ];
 
     $definitions = $this->privateMessageConfigFormManager->getDefinitions();
@@ -251,24 +254,6 @@ class ConfigForm extends ConfigFormBase {
    * {@inheritdoc}
    */
   public function submitForm(array &$form, FormStateInterface $form_state): void {
-    $this->config('private_message.settings')
-      ->set('enable_notifications', (bool) $form_state->getValue('enable_notifications'))
-      ->set('notify_by_default', (bool) $form_state->getValue('notify_by_default'))
-      ->set('notify_when_using', (string) $form_state->getValue('notify_when_using'))
-      ->set('number_of_seconds_considered_away', (int) $form_state->getValue('number_of_seconds_considered_away'))
-      ->set('hide_recipient_field_when_prefilled', (bool) $form_state->getValue('hide_recipient_field_when_prefilled'))
-      ->set('create_message_label', $form_state->getValue('create_message_label'))
-      ->set('save_message_label', $form_state->getValue('save_message_label'))
-      ->set('ban_mode', $form_state->getValue('ban_mode'))
-      ->set('ban_label', $form_state->getValue('ban_label'))
-      ->set('unban_label', $form_state->getValue('unban_label'))
-      ->set('ban_page_label', $form_state->getValue('ban_page_label'))
-      ->set('ban_message', $form_state->getValue('ban_message'))
-      ->set('autofocus_enable', (bool) $form_state->getValue('autofocus_enable'))
-      ->set('keys_send', $form_state->getValue('keys_send'))
-      ->set('remove_css', (bool) $form_state->getValue('remove_css'))
-      ->save();
-
     $definitions = $this->privateMessageConfigFormManager->getDefinitions();
     foreach ($definitions as $definition) {
       $instance = $this->privateMessageConfigFormManager->createInstance($definition['id']);
-- 
GitLab


From c3a3037a3249d2a7509d8afb74dd543ab1eebf11 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Tue, 3 Dec 2024 00:01:13 +0200
Subject: [PATCH 29/30] Addressing review remarks & suggestions

---
 private_message.api.php                                |  2 +-
 private_message.routing.yml                            |  2 +-
 src/Controller/PrivateMessageControllerInterface.php   |  2 +-
 .../Access/PrivateMessageAccessControlHandler.php      |  2 +-
 src/Entity/PrivateMessageThread.php                    |  2 --
 src/Entity/PrivateMessageThreadInterface.php           |  8 ++++++++
 src/Form/PrivateMessageDeleteForm.php                  |  3 ++-
 .../PrivateMessageThreadMembersNumberFormatter.php     |  4 +---
 .../PrivateMessageThreadMessageFormatter.php           |  2 +-
 .../PrivateMessageConfigFormBase.php                   |  4 ++--
 .../PrivateMessageThreadMemberConstraintValidator.php  |  4 ++--
 .../Constraint/UniqueBanConstraintValidator.php        | 10 +++++-----
 .../views/filter/PrivateMessageThreadIsUnread.php      |  3 ++-
 13 files changed, 27 insertions(+), 21 deletions(-)

diff --git a/private_message.api.php b/private_message.api.php
index c4321b97..d8aec0e1 100644
--- a/private_message.api.php
+++ b/private_message.api.php
@@ -21,7 +21,7 @@ use Drupal\private_message\Entity\PrivateMessageThreadInterface;
  * @param string $viewMode
  *   The view mode being rendered on the private message.
  */
-function hook_private_message_view_alter(array &$build, EntityInterface $privateMessage, $viewMode) {
+function hook_private_message_view_alter(array &$build, EntityInterface $privateMessage, string $viewMode): void {
   // Create a new class specific to the author of the message.
   $class = 'private-message-author-' . $privateMessage->getOwnerId();
   // Add the class to the wrapper.
diff --git a/private_message.routing.yml b/private_message.routing.yml
index 777d5ce8..b389f2f2 100644
--- a/private_message.routing.yml
+++ b/private_message.routing.yml
@@ -7,7 +7,7 @@ private_message.private_message_page:
     _permission: 'use private messaging system,access user profiles'
     _user_is_logged_in: 'TRUE'
   options:
-    no_cache: 'TRUE'
+    no_cache: TRUE
 
 entity.private_message_thread.canonical:
   path: '/private-messages/{private_message_thread}'
diff --git a/src/Controller/PrivateMessageControllerInterface.php b/src/Controller/PrivateMessageControllerInterface.php
index b1e8b39d..5ec0c2d9 100644
--- a/src/Controller/PrivateMessageControllerInterface.php
+++ b/src/Controller/PrivateMessageControllerInterface.php
@@ -41,7 +41,7 @@ interface PrivateMessageControllerInterface {
    */
   public function configPage(): array;
 
-    /**
+  /**
    * The page for preparing to uninstall the module.
    *
    * @return array
diff --git a/src/Entity/Access/PrivateMessageAccessControlHandler.php b/src/Entity/Access/PrivateMessageAccessControlHandler.php
index 6985c23f..cad95a2a 100644
--- a/src/Entity/Access/PrivateMessageAccessControlHandler.php
+++ b/src/Entity/Access/PrivateMessageAccessControlHandler.php
@@ -85,7 +85,7 @@ class PrivateMessageAccessControlHandler extends EntityAccessControlHandler impl
    * Separate from the checkAccess because the entity does not yet exist, it
    * will be created during the 'add' process.
    */
-  protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
+  protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL): AccessResultInterface {
     return AccessResult::allowedIfHasPermission($account, 'use private messaging system');
   }
 
diff --git a/src/Entity/PrivateMessageThread.php b/src/Entity/PrivateMessageThread.php
index 520bddcb..dc5e291e 100644
--- a/src/Entity/PrivateMessageThread.php
+++ b/src/Entity/PrivateMessageThread.php
@@ -320,8 +320,6 @@ class PrivateMessageThread extends ContentEntityBase implements PrivateMessageTh
 
   /**
    * {@inheritdoc}
-   *
-   * @todo Add to interface?
    */
   public function getUpdatedTime(): int {
     return (int) $this->get('updated')->value;
diff --git a/src/Entity/PrivateMessageThreadInterface.php b/src/Entity/PrivateMessageThreadInterface.php
index 598f4e8d..c21fec7a 100644
--- a/src/Entity/PrivateMessageThreadInterface.php
+++ b/src/Entity/PrivateMessageThreadInterface.php
@@ -206,6 +206,14 @@ interface PrivateMessageThreadInterface extends ContentEntityInterface {
    */
   public function filterUserDeletedMessages(AccountInterface $account): array;
 
+  /**
+   * Returns the thread last updated time.
+   *
+   * @return int
+   *   Thread last updated time.
+   */
+  public function getUpdatedTime(): int;
+
   /**
    * Clears cache tags related to private message thread entities.
    */
diff --git a/src/Form/PrivateMessageDeleteForm.php b/src/Form/PrivateMessageDeleteForm.php
index 335ef645..0eb95cce 100644
--- a/src/Form/PrivateMessageDeleteForm.php
+++ b/src/Form/PrivateMessageDeleteForm.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
 
 namespace Drupal\private_message\Form;
 
+use Drupal\Component\Render\MarkupInterface;
 use Drupal\Core\Entity\ContentEntityDeleteForm;
 
 /**
@@ -14,7 +15,7 @@ class PrivateMessageDeleteForm extends ContentEntityDeleteForm {
   /**
    * {@inheritdoc}
    */
-  protected function getDeletionMessage(): string {
+  protected function getDeletionMessage(): MarkupInterface|string {
     return $this->t('The message has been deleted.');
   }
 
diff --git a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMembersNumberFormatter.php b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMembersNumberFormatter.php
index fbe3d8ef..83aa25cd 100644
--- a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMembersNumberFormatter.php
+++ b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMembersNumberFormatter.php
@@ -71,13 +71,11 @@ class PrivateMessageThreadMembersNumberFormatter extends FormatterBase implement
     $users_num = count($items);
     $suffix = $this->getSetting('members_number_suffix');
 
-    $element = [
+    return [
       '#prefix' => '<div class="private-message-recipients-number">',
       '#suffix' => '</div>',
       '#markup' => "$users_num $suffix",
     ];
-
-    return $element;
   }
 
 }
diff --git a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php
index a2b5b25e..ad44e311 100644
--- a/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php
+++ b/src/Plugin/Field/FieldFormatter/PrivateMessageThreadMessageFormatter.php
@@ -172,7 +172,7 @@ class PrivateMessageThreadMessageFormatter extends FormatterBase implements Cont
     $element['view_mode'] = [
       '#type' => 'select',
       '#title' => $this->t('Private Message view mode'),
-      '#options' => $this->entityDisplayRepository->getViewModeOptions('private_message', TRUE),
+      '#options' => $this->entityDisplayRepository->getViewModeOptions('private_message'),
       '#default_value' => $this->getSetting('view_mode'),
     ];
 
diff --git a/src/Plugin/PrivateMessageConfigForm/PrivateMessageConfigFormBase.php b/src/Plugin/PrivateMessageConfigForm/PrivateMessageConfigFormBase.php
index 51123c73..99b7ab0a 100644
--- a/src/Plugin/PrivateMessageConfigForm/PrivateMessageConfigFormBase.php
+++ b/src/Plugin/PrivateMessageConfigForm/PrivateMessageConfigFormBase.php
@@ -16,8 +16,8 @@ abstract class PrivateMessageConfigFormBase extends PluginBase implements Privat
 
   public function __construct(
     array $configuration,
-    $plugin_id,
-    $plugin_definition,
+    string $plugin_id,
+    mixed $plugin_definition,
     protected ConfigFactoryInterface $configFactory,
   ) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
diff --git a/src/Plugin/Validation/Constraint/PrivateMessageThreadMemberConstraintValidator.php b/src/Plugin/Validation/Constraint/PrivateMessageThreadMemberConstraintValidator.php
index 83ccc8bf..bf751e76 100644
--- a/src/Plugin/Validation/Constraint/PrivateMessageThreadMemberConstraintValidator.php
+++ b/src/Plugin/Validation/Constraint/PrivateMessageThreadMemberConstraintValidator.php
@@ -18,8 +18,8 @@ class PrivateMessageThreadMemberConstraintValidator extends ConstraintValidator
   /**
    * {@inheritdoc}
    */
-  public function validate($items, Constraint $constraint): void {
-    $users = $items->referencedEntities();
+  public function validate($value, Constraint $constraint): void {
+    $users = $value->referencedEntities();
     foreach ($users as $user) {
       if (!$user->hasPermission('use private messaging system')) {
         $this->context->addViolation($constraint->userPrivateMessagePermissionError, ['%user' => $user->getDisplayName()]);
diff --git a/src/Plugin/Validation/Constraint/UniqueBanConstraintValidator.php b/src/Plugin/Validation/Constraint/UniqueBanConstraintValidator.php
index 70c8d841..77e697d7 100644
--- a/src/Plugin/Validation/Constraint/UniqueBanConstraintValidator.php
+++ b/src/Plugin/Validation/Constraint/UniqueBanConstraintValidator.php
@@ -25,18 +25,18 @@ class UniqueBanConstraintValidator extends ConstraintValidator implements Contai
   /**
    * {@inheritdoc}
    */
-  public function validate($entity, Constraint $constraint): void {
-    assert($entity instanceof PrivateMessageBan);
+  public function validate($value, Constraint $constraint): void {
+    assert($value instanceof PrivateMessageBan);
 
     $storage = $this->entityTypeManager->getStorage('private_message_ban');
     $query = $storage->getQuery()
       ->accessCheck(FALSE)
-      ->condition('owner', $entity->getOwnerId(), '=')
-      ->condition('target', $entity->getTargetId(), '=');
+      ->condition('owner', $value->getOwnerId(), '=')
+      ->condition('target', $value->getTargetId(), '=');
 
     if ($query->range(0, 1)->execute()) {
       $this->context->buildViolation($constraint->message, [
-        '%user' => $entity->getTarget()->getDisplayName(),
+        '%user' => $value->getTarget()->getDisplayName(),
       ])->addViolation();
     }
   }
diff --git a/src/Plugin/views/filter/PrivateMessageThreadIsUnread.php b/src/Plugin/views/filter/PrivateMessageThreadIsUnread.php
index dd5b841c..d37d3c39 100644
--- a/src/Plugin/views/filter/PrivateMessageThreadIsUnread.php
+++ b/src/Plugin/views/filter/PrivateMessageThreadIsUnread.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
 
 namespace Drupal\private_message\Plugin\views\filter;
 
+use Drupal\Component\Render\MarkupInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\views\Attribute\ViewsFilter;
 use Drupal\views\Plugin\ViewsHandlerManager;
@@ -68,7 +69,7 @@ class PrivateMessageThreadIsUnread extends FilterPluginBase {
   /**
    * {@inheritdoc}
    */
-  public function adminSummary(): \Stringable|string {
+  public function adminSummary(): MarkupInterface|string {
     return '';
   }
 
-- 
GitLab


From bcd54c20c02c12b52d3be38844d389606d41648a Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Tue, 3 Dec 2024 11:46:47 +0200
Subject: [PATCH 30/30] QA remarks

---
 src/Form/ConfigForm.php | 39 +++++++++++++++++++++++++++++++--------
 1 file changed, 31 insertions(+), 8 deletions(-)

diff --git a/src/Form/ConfigForm.php b/src/Form/ConfigForm.php
index a8ecdcb4..841cfc79 100644
--- a/src/Form/ConfigForm.php
+++ b/src/Form/ConfigForm.php
@@ -78,7 +78,11 @@ class ConfigForm extends ConfigFormBase {
     $form['pm_core']['notifications']['enable_notifications'] = [
       '#type' => 'checkbox',
       '#title' => $this->t('Enable notifications'),
-      '#config_target' => new ConfigTarget('private_message.settings', 'enable_notifications', NULL, fn($value): bool => boolval($value)),
+      '#config_target' => new ConfigTarget(
+        configName: 'private_message.settings',
+        propertyPath: 'enable_notifications',
+        toConfig: fn($value): bool => boolval($value),
+      ),
     ];
 
     $form['pm_core']['notifications']['notify_by_default'] = [
@@ -88,7 +92,12 @@ class ConfigForm extends ConfigFormBase {
         $this->t('Do not send notifications (users can opt-in)'),
         $this->t('Send notifications (users can opt-out)'),
       ],
-      '#config_target' => new ConfigTarget('private_message.settings', 'notify_by_default', NULL, fn($value): bool => boolval($value)),
+      '#config_target' => new ConfigTarget(
+        configName: 'private_message.settings',
+        propertyPath: 'notify_by_default',
+        fromConfig: fn($value): int => intval($value),
+        toConfig: fn($value): bool => boolval($value),
+      ),
       '#states' => [
         'visible' => [
           ':input[name="enable_notifications"]' => ['checked' => TRUE],
@@ -115,7 +124,11 @@ class ConfigForm extends ConfigFormBase {
     $form['pm_core']['notifications']['number_of_seconds_considered_away'] = [
       '#type' => 'number',
       '#title' => $this->t('The number of seconds after which a user should be considered as not viewing a thread'),
-      '#config_target' => new ConfigTarget('private_message.settings', 'number_of_seconds_considered_away', NULL, fn($value): int => intval($value)),
+      '#config_target' => new ConfigTarget(
+        configName: 'private_message.settings',
+        propertyPath: 'number_of_seconds_considered_away',
+        toConfig: fn($value): int => intval($value),
+      ),
       '#description' => $this->t('When users have a private message thread open, calls to the server update the last time they have accessed the thread. This setting determines how many seconds after they have closed the thread, they should be considered as not accessing the thread anymore. Users will be able to override this value on their profile settings page.'),
       '#states' => [
         'visible' => [
@@ -129,15 +142,22 @@ class ConfigForm extends ConfigFormBase {
       '#type' => 'checkbox',
       '#title' => $this->t('Hide recipient field when recipient is in the URL'),
       '#description' => $this->t('Links can be created to the private message page, passing the recipient in the URL. If this box is checked, the recipient field will be hidden when the recipient is passed in the URL.'),
-      '#config_target' => new ConfigTarget('private_message.settings', 'hide_recipient_field_when_prefilled', NULL, fn($value): bool => boolval($value)),
+      '#config_target' => new ConfigTarget(
+        configName: 'private_message.settings',
+        propertyPath: 'hide_recipient_field_when_prefilled',
+        toConfig: fn($value): bool => boolval($value),
+      ),
     ];
 
     $form['pm_core']['autofocus_enable'] = [
       '#type' => 'checkbox',
       '#title' => $this->t('Enable autofocus'),
       '#description' => $this->t('This option allows you to put the autofocus in the message textarea.'),
-      '#default_value' => (int) $config->get('autofocus_enable'),
-      '#config_target' => new ConfigTarget('private_message.settings', 'autofocus_enable', NULL, fn($value): bool => boolval($value)),
+      '#config_target' => new ConfigTarget(
+        configName: 'private_message.settings',
+        propertyPath: 'autofocus_enable',
+        toConfig: fn($value): bool => boolval($value),
+      ),
     ];
 
     $form['pm_core']['keys_send'] = [
@@ -156,7 +176,11 @@ class ConfigForm extends ConfigFormBase {
       '#type' => 'checkbox',
       '#title' => $this->t('Remove the default CSS of the module'),
       '#description' => $this->t('This option can break the features of the module and it is only for developers who want to override the styles more easily.'),
-      '#config_target' => new ConfigTarget('private_message.settings', 'remove_css', NULL, fn($value): bool => boolval($value)),
+      '#config_target' => new ConfigTarget(
+        configName: 'private_message.settings',
+        propertyPath: 'remove_css',
+        toConfig: fn($value): bool => boolval($value),
+      ),
     ];
 
     $form['pm_labels'] = [
@@ -212,7 +236,6 @@ class ConfigForm extends ConfigFormBase {
     $form['pm_block']['ban_page_label'] = [
       '#type' => 'textfield',
       '#title' => $this->t("Text to go to the ban page"),
-      '#default_value' => $config->get('ban_page_label'),
       '#config_target' => 'private_message.settings:ban_page_label',
     ];
 
-- 
GitLab