foldershare-8.x-1.2/src/Utilities/UserUtilities.php

src/Utilities/UserUtilities.php
<?php

namespace Drupal\foldershare\Utilities;

use Drupal\Core\Database\Database;
use Drupal\user\Entity\User;

/**
 * Defines static utility functions for working with users.
 *
 * The functions in this class support user queries based upon the user's
 * account name, account email address, and display name.
 *
 * <B>Warning:</B> This class is strictly internal to the FolderShare
 * module. The class's existance, name, and content may change from
 * release to release without any promise of backwards compatability.
 *
 * @ingroup foldershare
 */
final class UserUtilities {

  /*--------------------------------------------------------------------
   *
   * Configuration.
   *
   *-------------------------------------------------------------------*/

  /**
   * Returns TRUE if the "Real name" contributed module is installed.
   *
   * @return bool
   *   Returns TRUE if installed.
   */
  public static function isRealnameInstalled() {
    return \Drupal::moduleHandler()->moduleExists('realname');
  }

  /**
   * Returns the configured name for the anonymous account.
   *
   * The anonymous (uid = 0) account is a virtual account for visitors that
   * are not logged in. The display name for the account can be set via
   * a User module configuration setting.
   *
   * The configured name is typically the display name for the account,
   * but display name hook implementations can override it.
   *
   * @return string
   *   The configured name for the anonymous account.
   */
  public static function getAnonymousName() {
    return \Drupal::config('user.settings')->get('anonymous');
  }

  /**
   * Returns the names of modules implementing the display name hook.
   *
   * The User::getDisplayName() method invokes the 'user_format_name_alter'
   * hook used by modules to override the account name and provide a more
   * descriptive name, such as a user's full name. The common "Real name"
   * module is one such module, which uses tokens to assemble a name from
   * one or more other fields on a User entity.
   *
   * This method returns a list of modules implementing the hook.
   *
   * @return string[]
   *   Returns the machine names of modules implementing the display name
   *   hook.
   */
  public static function getDisplayNameHookModules() {
    return \Drupal::moduleHandler()
      ->getImplementations('user_format_name_alter');
  }

  /*--------------------------------------------------------------------
   *
   * Functions.
   *
   *-------------------------------------------------------------------*/

  /**
   * Returns the user ID for a given user name, display name, or email address.
   *
   * Database tables are queried for an exact case insensitive match.
   *
   * Display name queries are only available if the third-party "Real name"
   * module is installed. The module uses tokens to assemble a name from
   * site-defined fields, then caches that name in a database table that is
   * queried here.
   *
   * @param string $name
   *   The account name, display name, or email address of a user.
   *
   * @return int
   *   Returns the user ID for the matched user, or (-1) if not found.
   *
   * @see ::findUserByAccountName()
   * @see ::findUserByAccountEmail()
   * @see ::findUserByDisplayName()
   * @see ::findSimilarUsers()
   */
  public static function findUser(string $name) {
    $uid = self::findUserByAccountName($name);
    if ($uid !== (-1)) {
      return $uid;
    }

    $uid = self::findUserByAccountEmail($name);
    if ($uid !== (-1)) {
      return $uid;
    }

    $uid = self::findUserByDisplayName($name, FALSE);
    if ($uid !== (-1)) {
      return $uid;
    }

    return (-1);
  }

  /**
   * Returns the user ID for a given user account name.
   *
   * Database tables are queried for an exact case insensitive match.
   *
   * Account names are expected to be unique within a site. A database
   * table query can therefore return at most one entry.
   *
   * @param string $name
   *   The account name of a user.
   *
   * @return int
   *   Returns the user ID for the matched user, or (-1) if not found.
   *
   * @see ::findUser()
   * @see ::findUserByAccountEmail()
   * @see ::findUserByDisplayName()
   * @see ::findSimilarUsers()
   */
  public static function findUserByAccountName(string $name) {
    // Note: This query could be done by user_load_by_name() in the user
    // module. However, that function does a case *sensitive* search and
    // it loads the entity. We want a case *insensitive* search and we
    // only want the user ID.
    $connection = Database::getConnection();
    $select = $connection->select('users_field_data', 'u');
    $select->addField('u', 'uid', 'uid');
    $select->addExpression('LOWER(u.name)', 'unamelower');
    $select->condition('unamelower', mb_strtolower($name), '=');
    $select->range(0, 1);
    $uids = $select->execute()->fetchCol(0);

    if (empty($uids) === TRUE) {
      return (-1);
    }

    // Return the first match. There should be only one since account names
    // are required to be unique.
    return (int) $uids[0];
  }

  /**
   * Returns the user ID for a given user account email address.
   *
   * Database tables are queried for an exact case insensitive match.
   *
   * Account email addresses need not be unique within a site. Multiple
   * accounts may have the same address. When there are multiple matches,
   * this function returns the match with the lowest user ID, which will
   * be the earliest account created.
   *
   * @param string $email
   *   The account email address of a user.
   *
   * @return int
   *   Returns the user ID for the matched user, or (-1) if not found.
   *
   * @see ::findUser()
   * @see ::findUserByAccountName()
   * @see ::findUserByDisplayName()
   * @see ::findSimilarUsers()
   */
  public static function findUserByAccountEmail(string $email) {
    // Note: This query could be done by user_load_by_mail() in the user
    // module. However, that function does a case *sensitive* search and
    // it loads the entity. We want a case *insensitive* search and we
    // only want the user ID.
    $connection = Database::getConnection();
    $select = $connection->select('users_field_data', 'u');
    $select->addField('u', 'uid', 'uid');
    $select->addExpression('LOWER(u.mail)', 'umaillower');
    $select->condition('umaillower', mb_strtolower($email), '=');
    $select->orderBy('uid');
    $select->range(0, 1);
    $uids = $select->execute()->fetchCol(0);

    if (empty($uids) === TRUE) {
      return (-1);
    }

    // Return the first match. It is possible for more than one account to
    // have the same email address, though this is unlikely. The order-by
    // clause above has insured that the first value has the lowest user ID.
    return (int) $uids[0];
  }

  /**
   * Returns the user ID for a given user display name.
   *
   * This method searches for a user entity with a matching display name,
   * ignoring case. If no match is found, (-1) is returned.
   *
   * There are three cases handled:
   *
   * 1. There are no implementations of the 'user_format_name_alter' hook, and
   *    therefore the display name is the account name. A special case is
   *    handled for anonymous, which uses the configured display name.
   *
   * 2. There is one hook implementation and it is for the common "Real name"
   *    contributed module. A database search on its tables is then possible.
   *
   * 3. There are one or more hook implementations and they are not for
   *    the "Real name" module. A slow search through every User entity is
   *    required to find the display name.
   *
   * Cases 1 and 2 are always handled. Case 3 is performed only if
   * $searchUsers is TRUE.
   *
   * @param string $name
   *   The display name of a user.
   * @param bool $searchUsers
   *   (optional, default = TRUE) When TRUE, the method fails and returns
   *   (-1) if there are no known shortcuts to getting the display name,
   *   and the fallback would require loading every User entity, which can
   *   be slow.
   *
   * @return int
   *   Returns the user ID for the matched user, or (-1) if not found.
   *
   * @see ::findUser()
   * @see ::findUserByAccountName()
   * @see ::findUserByAccountEmail()
   * @see ::findSimilarUsers()
   * @see ::isRealnameInstalled()
   * @see ::getDisplayNameHookModules()
   */
  public static function findUserByDisplayName(
    string $name,
    bool $searchUsers = FALSE) {

    $lowerName = mb_strtolower($name);

    $hookModules = self::getDisplayNameHookModules();

    if (empty($hookModules) === TRUE) {
      // There are no display name hook implementations.
      //
      // The display name falls back to the account name. Anonymous is an
      // exception because it always falls back to the configured name for
      // the account.
      $anonymousName = mb_strtolower(
        \Drupal::config('user.settings')->get('anonymous'));
      if ($anonymousName === $lowerName) {
        return 0;
      }

      return self::findUserByAccountName($name);
    }

    if (count($hookModules) === 1 && $hookModules[0] === 'realname') {
      // There is one display name hook implementation and it is the "realname"
      // contributed module.  This is a common case.
      //
      // We can search realname's database table of cached computed display
      // names. However, the table does not include a name for every user.
      // If the fields used by a realname configuration are empty for an
      // account, the display name will be empty. Additionally, a value is
      // only computed for a user when a display name is needed. Until then,
      // there will be no entry in realname's table for the user.
      $connection = Database::getConnection();
      $select = $connection->select('realname', 'r');
      $select->addField('r', 'uid', 'uid');
      $select->addField('r', 'realname', 'realname');
      $select->addExpression('LOWER(r.realname)', 'rrealnamelower');
      $select->condition('rrealnamelower', $lowerName, '=');
      $select->orderBy('uid');
      $select->range(0, 1);
      $qresults = $select->execute()->fetchAll();

      if (empty($qresults) === TRUE) {
        // There is no entry for the user in realname's table. Check the
        // account name.
        return self::findUserByAccountName($name);
      }

      if (empty($qresults[0]->realname) === TRUE) {
        // There is an entry for the user, but it is empty. Check the
        // account name.
        return self::findUserByAccountName($name);
      }

      return (int) $qresults[0]->uid;
    }

    // There are either multiple hook implementations, or there is just one
    // implementation but it is not the "realname" module. The only way to
    // get the display name is by repeated calls to User::getDisplayName().
    // This requires loading all User entities, which will be slooooow.
    if ($searchUsers === FALSE) {
      // No easy way to get the display name, and search disabled.
      return (-1);
    }

    $uids = self::getAllUserIds();
    foreach ($uids as $uid) {
      $user = User::load($uid);
      if ($user !== NULL &&
          mb_strtolower($user->getDisplayName()) === $lowerName) {
        return $uid;
      }
      unset($user);
    }

    return (-1);
  }

  /**
   * Returns a list of user IDs that are similar to a given name.
   *
   * Database tables are queried for a case insensitive match that includes
   * the given text somewhere within the account name, account email, or
   * display name.
   *
   * The user entity's account names are always searched for matches with
   * the given name.
   *
   * If the third-party "Real name" module is installed, its table of
   * display names is searched for matches with the given name.
   *
   * If $matchEmail is TRUE, the user entity's email addresses are searched
   * for matches with the given name.
   *
   * The returned list of user IDs is ordered alphabetically on the
   * account name.
   *
   * @param string $name
   *   The name or name fragment to search for.
   * @param bool $matchEmail
   *   (optional, default = FALSE) Whether to look for a match against user
   *   email addresses.
   * @param bool $excludeBlocked
   *   (optional, default = TRUE) Whether to include blocked accounts in the
   *   returned list.
   * @param int[] $excludeUids
   *   (optional, default = []) A list of user IDs to exclude from the returned
   *   list.
   * @param int $maxReturn
   *   (optional, default = 10) The maximum number of matches to return. If
   *   this is <= 0, all matches are returned.
   *
   * @return int[]
   *   Returns a list of integer User entity IDs, or an empty list if no
   *   matches are found. IDs are sorted on the account name.
   *
   * @see ::findUser()
   * @see ::findUserByAccountName()
   * @see ::findUserByAccountEmail()
   * @see ::findUserByDisplayName()
   * @see ::isRealnameInstalled()
   */
  public static function findSimilarUsers(
    string $name,
    bool $matchEmail = FALSE,
    bool $excludeBlocked = TRUE,
    array $excludeUids = [],
    int $maxReturn = 10) {

    // Query the user entity's fields to get the user ID and account name
    // matches.
    $connection = Database::getConnection();
    $select = $connection->select('users_field_data', 'u');
    $select->addField('u', 'uid', 'uid');

    $likeGroup = $select->orConditionGroup();
    $likeGroup->condition('u.name', '%' . $name . '%', 'LIKE');
    $select->orderBy('u.name', 'ASC');

    // Optionally search the email address too.
    if ($matchEmail === TRUE) {
      $likeGroup->condition('u.mail', '%' . $name . '%', 'LIKE');
    }

    // If the "Real name" module is enabled, check its fields for display
    // name matches.
    if (self::isRealnameInstalled() === TRUE) {
      $select->leftJoin('realname', 'r', '(r.uid = u.uid)');
      $likeGroup->condition('r.realname', '%' . $name . '%', 'LIKE');
    }

    // Require a match AND optionally exclude blocked users and
    // those on an exclude list.
    $allowGroup = $select->andConditionGroup();
    $allowGroup->condition($likeGroup);
    if ($excludeBlocked === TRUE) {
      $allowGroup->condition('u.status', 1);
    }

    if (empty($excludeUids) === FALSE) {
      $allowGroup->condition('u.uid', $excludeUids, 'NOT IN');
    }

    $select = $select->condition($allowGroup);

    // Optioinally limit the number of returned results.
    if ($maxReturn > 0) {
      $select->range(0, $maxReturn);
    }

    // Get the results and insure they are all integers.
    $nums = $select->execute()->fetchCol(0);
    $uids = [];
    foreach ($nums as $num) {
      $uids[] = (int) $num;
    }

    return $uids;
  }

  /**
   * Returns a list of all user IDs.
   *
   * @return int[]
   *   Returns a list of all user IDs.
   *
   * @see ::getAllAccountNames()
   * @see ::getAllDisplayNames()
   */
  public static function getAllUserIds() {
    $uids = \Drupal::entityTypeManager()
      ->getStorage('user')
      ->getQuery()
      ->execute();

    $n = count($uids);
    for ($i = 0; $i < $n; ++$i) {
      $uids[$i] = (int) $uids[$i];
    }

    return $uids;
  }

  /**
   * Returns an array of user account names with user ID keys.
   *
   * The returned list is not sorted.
   *
   * @return array
   *   Returns an associative array with user IDs as keys and account
   *   names as values.
   *
   * @see ::getAllUserIds()
   * @see ::getAllDisplayNames()
   */
  public static function getAllAccountNames() {
    $connection = Database::getConnection();
    $select = $connection->select('users_field_data', 'u');
    $select->addField('u', 'uid', 'uid');
    $select->addField('u', 'name', 'name');
    $select->orderby('name');
    $qresults = $select->execute()->fetchAll();

    $results = [];
    foreach ($qresults as $r) {
      $results[$r->uid] = $r->name;
    }

    return $results;
  }

  /**
   * Returns an array of user display names with user ID keys.
   *
   * The returned list is not sorted.
   *
   * @return array
   *   Returns an associative array with user IDs as keys and display
   *   names as values.
   *
   * @see ::getAllUserIds()
   * @see ::getAllAccountNames()
   * @see ::getDisplayNameHookModules()
   */
  public static function getAllDisplayNames() {
    $hookModules = self::getDisplayNameHookModules();

    if (empty($hookModules) === TRUE) {
      // There are no display name hook implementations. All display names
      // are just the account name, except for anonymous.
      $results = self::getAllAccountNames();
      $results[0] = self::getAnonymousName();
      return $results;
    }

    if (count($hookModules) === 1 && $hookModules[0] === 'realname') {
      // There is one display name hook implementation and it is the "realname"
      // contributed module.  This is a common case.
      //
      // Use realname's table of cached computed display names. However,
      // the table does not include a name for every user.  If the fields
      // used by a realname configuration are empty for an account, the
      // display name will be empty. Additionally, a value is only computed
      // for a user when a display name is needed. Until then, there will be
      // no entry in realname's table for the user.
      //
      // If there is no display name in the table yet, fall back to the
      // account name.
      $connection = Database::getConnection();
      $select = $connection->select('users_field_data', 'u');
      $select->addField('u', 'uid', 'uid');
      $select->addField('u', 'name', 'name');
      $select->leftJoin('realname', 'r', '(r.uid = u.uid)');
      $select->addField('r', 'realname', 'realname');
      $select->orderBy('uid');
      $qresults = $select->execute()->fetchAll();

      $results = [];
      foreach ($qresults as $r) {
        if (empty($r->realname) === TRUE) {
          $results[$r->uid] = $r->name;
        }
        else {
          $results[$r->uid] = $r->realname;
        }
      }

      if (isset($results[0]) === FALSE) {
        $results[0] = self::getAnonymousName();
      }

      return $results;
    }

    // There are either multiple hook implementations, or there is just one
    // implementation but it is not the "realname" module. The only way to
    // get the display name is by repeated calls to User::getDisplayName().
    // This requires loading all User entities, which will be slooooow.
    $uids = self::getAllUserIds();
    $results = [];
    foreach ($uids as $uid) {
      $user = User::load($uid);
      if ($user !== NULL) {
        $results[$user->id()] = $user->getDisplayName();
      }
      unset($user);
    }

    return $results;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc