class SwitchUserListHelper

Switch user helper service.

Hierarchy

Expanded class hierarchy of SwitchUserListHelper

2 files declare their use of SwitchUserListHelper
SwitchUserBlock.php in src/Plugin/Block/SwitchUserBlock.php
SwitchUserPageForm.php in src/Form/SwitchUserPageForm.php
1 string reference to 'SwitchUserListHelper'
devel.services.yml in ./devel.services.yml
devel.services.yml
1 service uses SwitchUserListHelper
devel.switch_user_list_helper in ./devel.services.yml
Drupal\devel\SwitchUserListHelper

File

src/SwitchUserListHelper.php, line 20

Namespace

Drupal\devel
View source
class SwitchUserListHelper {
  use StringTranslationTrait;
  
  /**
   * The Current User object.
   */
  protected AccountInterface $currentUser;
  
  /**
   * The user storage.
   */
  protected UserStorageInterface $userStorage;
  
  /**
   * The redirect destination service.
   */
  protected RedirectDestinationInterface $redirectDestination;
  
  /**
   * The role storage.
   */
  protected RoleStorageInterface $roleStorage;
  
  /**
   * Constructs a new SwitchUserListHelper service.
   *
   * @param \Drupal\Core\Session\AccountInterface $current_user
   *   Current user.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Routing\RedirectDestinationInterface $redirect_destination
   *   The redirect destination service.
   * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
   *   The translation manager.
   */
  public function __construct(AccountInterface $current_user, EntityTypeManagerInterface $entity_type_manager, RedirectDestinationInterface $redirect_destination, TranslationInterface $string_translation) {
    $this->currentUser = $current_user;
    $this->userStorage = $entity_type_manager->getStorage('user');
    $this->redirectDestination = $redirect_destination;
    $this->stringTranslation = $string_translation;
    $this->roleStorage = $entity_type_manager->getStorage('user_role');
  }
  
  /**
   * Provides the list of accounts that can be used for the user switch.
   *
   * Inactive users are omitted from all of the following db selects. Users
   * with 'switch users' permission and anonymous user if include_anon property
   * is set to TRUE, are prioritized.
   *
   * @param int $limit
   *   The number of accounts to use for the list.
   * @param bool $include_anonymous
   *   Whether or not to include the anonymous user.
   *
   * @return \Drupal\Core\Session\AccountInterface[]
   *   List of accounts to be used for the switch.
   */
  public function getUsers(int $limit = 50, bool $include_anonymous = FALSE) {
    $limit = $include_anonymous ? $limit - 1 : $limit;
    // Users with 'switch users' permission are prioritized so get these first.
    $query = $this->userStorage
      ->getQuery()
      ->condition('uid', 0, '>')
      ->condition('status', 0, '>')
      ->sort('access', 'DESC')
      ->accessCheck(FALSE)
      ->range(0, $limit);
    /** @var array<string, RoleInterface> $roles */
    $roles = $this->roleStorage
      ->loadMultiple();
    unset($roles[AccountInterface::ANONYMOUS_ROLE]);
    $roles = array_filter($roles, static fn($role): bool => $role->hasPermission('switch users'));
    if ($roles !== [] && !isset($roles[RoleInterface::AUTHENTICATED_ID])) {
      $query->condition('roles', array_keys($roles), 'IN');
    }
    $user_ids = $query->execute();
    // If we don't have enough users with 'switch users' permission, add more
    // users until we hit $limit.
    if (count($user_ids) < $limit) {
      $query = $this->userStorage
        ->getQuery()
        ->condition('uid', 0, '>')
        ->condition('status', 0, '>')
        ->sort('access', 'DESC')
        ->accessCheck(FALSE)
        ->range(0, $limit);
      // Exclude the prioritized user ids if the previous query returned some.
      if (!empty($user_ids)) {
        $query->condition('uid', array_keys($user_ids), 'NOT IN');
        $query->range(0, $limit - count($user_ids));
      }
      $user_ids += $query->execute();
    }
    /** @var \Drupal\Core\Session\AccountInterface[] $accounts */
    $accounts = $this->userStorage
      ->loadMultiple($user_ids);
    if ($include_anonymous) {
      $anonymous = new AnonymousUserSession();
      $accounts[$anonymous->id()] = $anonymous;
    }
    // Syntax comes from https://php.watch/versions/8.2/partially-supported-callable-deprecation.
    uasort($accounts, self::class . '::sortUserList');
    return $accounts;
  }
  
  /**
   * Builds the user listing as renderable array.
   *
   * @param \Drupal\Core\Session\AccountInterface[] $accounts
   *   The accounts to be rendered in the list.
   *
   * @return array
   *   A renderable array.
   */
  public function buildUserList(array $accounts) : array {
    $links = [];
    foreach ($accounts as $account) {
      $links[$account->id()] = [
        'title' => $account->getDisplayName(),
        'url' => Url::fromRoute('devel.switch', [
          'name' => $account->getAccountName(),
        ]),
        'query' => $this->redirectDestination
          ->getAsArray(),
        'attributes' => [
          'title' => $account->hasPermission('switch users') ? $this->t('This user can switch back.') : $this->t('Caution: this user will be unable to switch back.'),
        ],
      ];
      if ($account->isAnonymous()) {
        $links[$account->id()]['url'] = Url::fromRoute('user.logout');
      }
      if ($this->currentUser
        ->id() === $account->id()) {
        $links[$account->id()]['title'] = new FormattableMarkup('<strong>%user</strong>', [
          '%user' => $account->getDisplayName(),
        ]);
      }
    }
    return [
      '#theme' => 'links',
      '#links' => $links,
      '#attached' => [
        'library' => [
          'devel/devel',
        ],
      ],
    ];
  }
  
  /**
   * Helper callback for uasort() to sort accounts by last access.
   *
   * @param \Drupal\Core\Session\AccountInterface $a
   *   First account.
   * @param \Drupal\Core\Session\AccountInterface $b
   *   Second account.
   *
   * @return int
   *   Result of comparing the last access times:
   *   - -1 if $a was more recently accessed
   *   -  0 if last access times compare equal
   *   -  1 if $b was more recently accessed
   */
  public static function sortUserList(AccountInterface $a, AccountInterface $b) : int {
    $a_access = (int) $a->getLastAccessedTime();
    $b_access = (int) $b->getLastAccessedTime();
    if ($a_access === $b_access) {
      return 0;
    }
    // User never access to site.
    if ($a_access === 0) {
      return 1;
    }
    return $a_access > $b_access ? -1 : 1;
  }

}

Members

Title Sort descending Modifiers Object type Summary Overrides
StringTranslationTrait::$stringTranslation protected property The string translation service. 3
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
SwitchUserListHelper::$currentUser protected property The Current User object.
SwitchUserListHelper::$redirectDestination protected property The redirect destination service.
SwitchUserListHelper::$roleStorage protected property The role storage.
SwitchUserListHelper::$userStorage protected property The user storage.
SwitchUserListHelper::buildUserList public function Builds the user listing as renderable array.
SwitchUserListHelper::getUsers public function Provides the list of accounts that can be used for the user switch.
SwitchUserListHelper::sortUserList public static function Helper callback for uasort() to sort accounts by last access.
SwitchUserListHelper::__construct public function Constructs a new SwitchUserListHelper service.