foldershare-8.x-1.2/src/Controller/UserAutocompleteController.php

src/Controller/UserAutocompleteController.php
<?php

namespace Drupal\foldershare\Controller;

use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Controller\ControllerBase;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;

use Drupal\foldershare\Settings;
use Drupal\foldershare\Utilities\UserUtilities;

/**
 * Provides a user name autocomplete service.
 *
 * The user name autocomplete service is intended for use by forms that
 * require the user to type in a user or account name in order to
 * select a user. There are two primary forms that may use this:
 * - The change owner form that prompts for the account of the new owner
 *   of a selected item.
 * - The share form that prompts for the account of a user to be granted
 *   shared access to a file or folder.
 *
 * This autocomplete service is available on the route
 * "entity.foldershare.userautocomplete", defined in the module's routing file.
 *
 * Required URL arguments include:
 * - 'q=NAMEFRAGMENT' to provide a string to look up as part of a user's
 *   account name, display name, or email address.
 *
 * Optional URL arguments include:
 * - 'excludeUids=UIDLIST' to provide a comma-separated list of integer user IDs
 *   to NOT include in the returned autocomplete results. This may be used to
 *   exclude users in a 'Share' form that have already been granted access.
 * - 'excludeBlocked=1' to to prevent the returned list from including blocked
 *   users.
 *
 * The returned user list always excludes users with IDs in the 'excludeUids'
 * list, if any.
 *
 * The return list optionally excludes blocked users, if 'excludeBlocked' is 1.
 *
 * The returned user list is empty if:
 * - User autocomplete has been disabled for the module.
 * - The name fragment is empty.
 * - The name fragment does not match anything.
 *
 * The returned list is an array, formatted as JSON, sorted by user name.
 * Each entry is an array with 'value' and 'label' fields. The 'value' field
 * is the user account name, and the 'label' a label to show in an
 * autocomplete menu. Labels have one of these forms:
 * - Name only.
 * - Name with email address.
 * - Name with masked email address.
 *
 * The label style is determined by a module setting.
 *
 * The name is the account display name, and the email address the account's
 * email address (if any). When the masked form is used, the email address
 * is masked with '*'s for all name field characters, except the first and
 * last (e.g. "e*****e@example.com").
 *
 * @ingroup foldershare
 */
class UserAutocompleteController extends ControllerBase {

  /*---------------------------------------------------------------------
   *
   * Constants.
   *
   *---------------------------------------------------------------------*/

  /**
   * The default maximum number of results to return.
   *
   * @var int
   */
  const MAXIMUM_NUMBER_OF_RESULTS = 10;

  /*--------------------------------------------------------------------
   *
   * Fields - dependency injection.
   *
   *--------------------------------------------------------------------*/

  /**
   * The User entity storage manager, set at construction time.
   *
   * @var \Drupal\Core\Entity\EntityStorageInterface
   */
  protected $userStorage;

  /*--------------------------------------------------------------------
   *
   * Construction.
   *
   *--------------------------------------------------------------------*/

  /**
   * Constructs a new page.
   */
  public function __construct(
    EntityStorageInterface $userStorage) {
    $this->userStorage = $userStorage;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager')->getStorage('user'));
  }

  /*---------------------------------------------------------------------
   *
   * Autocomplete.
   *
   *---------------------------------------------------------------------*/

  /**
   * Responds to a text field's autocomplete request using a user name fragment.
   *
   * Auto-complete uses the given user name fragment to find all user names
   * that are similar to the name. If configured using the FolderShare admin
   * settings form, auto-complete may also look at email addresses to find
   * a good match.
   *
   * The returned list is intended for the 'Share' form to indicate users
   * with which to share content. There may already be users listed in the
   * form, and returning them in the auto-complete would be redundant. To
   * skip those users, an optional excludeUids list omits them from the returned
   * results.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The HTTP request, including two parameters:
   *   - 'q' has the text field input to auto-complete.
   *   - 'excludeUids' has a list of integer UIDs to exclude.
   *   - 'excludeBlocked' is 0 (FALSE) or 1 (TRUE) to indicate whether blocked
   *     user accounts should be excluded.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   The JSON response that contains an array of autocomplete content. Each
   *   entry in the JSON array is for a user. Each user entry is itself an
   *   array with 'value' and 'label' string values. The label is intended to
   *   be shown in an autocomplete menu, and the value is the value for that
   *   label.
   */
  public function autocomplete(Request $request) {
    //
    // Get parameters.
    // ---------------
    // 'q' is the query input from the text field. It must not be empty.
    // 'excludeUids' is the optional list of user IDs to skip in the returned
    // results. It can be missing or empty.
    $userNameFragment = $request->get('q', NULL);
    $excludeUids      = $request->get('excludeUids', []);
    $excludeBlocked   = $request->get('excludeBlocked', FALSE);

    $excludeBlocked = boolval($excludeBlocked);

    if (empty($userNameFragment) === TRUE) {
      // No user name fragment given. Return an empty response.
      return new JsonResponse([]);
    }

    //
    // Get auto-complete style.
    // ------------------------
    // The following styles are recognized:
    // - 'none'.
    // - 'name-only'.
    // - 'name-email'.
    // - 'name-masked-email'.
    $autocompleteStyle = Settings::getUserAutocompleteStyle();

    if ($autocompleteStyle === 'none') {
      // Auto-complete disabled. Return an empty response.
      return new JsonResponse([]);
    }

    $matchEmail = FALSE;
    if ($autocompleteStyle === 'name-email' ||
        $autocompleteStyle === 'name-masked-email') {
      $matchEmail = TRUE;
    }

    //
    // Get a list of similar users.
    // ----------------------------
    // Match the given name fragment against user account names and user
    // display names, if possible. Optionally match against user email
    // addresses. Optionally exclude the given list of user IDs and
    // blocked users.
    $uids = UserUtilities::findSimilarUsers(
      $userNameFragment,
      $matchEmail,
      $excludeBlocked,
      $excludeUids,
      self::MAXIMUM_NUMBER_OF_RESULTS);

    if (empty($uids) === TRUE) {
      // No match.
      return new JsonResponse([]);
    }

    //
    // Build returned JSON.
    // --------------------
    // Loop through the returned UIDs. For each one, we need:
    // - the display name.
    // - the email address (for appropriate auto-complete styles).
    //
    // If needed, the email address must be masked.
    $results = [];
    foreach ($uids as $uid) {
      // Load the user.
      $user = $this->userStorage->load($uid);
      if ($user === NULL) {
        // Invalid user.
        continue;
      }

      // Get the user's display name. If there is no full name, this falls
      // back to the account name.
      $userDisplayName = $user->getDisplayName();

      // Get the user's email address, if needed. Mask it, if needed.
      if ($autocompleteStyle === 'name-email' ||
          $autocompleteStyle === 'name-masked-email') {
        $userEmail = $user->getEmail();

        if ($autocompleteStyle === 'name-masked-email' &&
            empty($userEmail) === FALSE) {
          $userEmail = $this->maskEmail($userEmail);
        }

        if (empty($userEmail) === TRUE) {
          // The account has no email address, or it is malformed.
          // Skip it.
          $label = $this->t(
            '@userDisplayName',
            [
              '@userDisplayName' => $userDisplayName,
            ]);
        }
        else {
          $label = $this->t(
            '@userDisplayName (@userEmail)',
            [
              '@userDisplayName' => $userDisplayName,
              '@userEmail'       => $userEmail,
            ]);
        }
      }
      else {
        $label = $this->t(
          '@userDisplayName',
          [
            '@userDisplayName' => $userDisplayName,
          ]);
      }

      $results[] = [
        'value' => $user->getAccountName(),
        'label' => $label,
      ];

      unset($user);
    }

    return new JsonResponse($results);
  }

  /**
   * Returns a masked version of a given email address.
   *
   * Masking keeps the first and last characters of the name portion of
   * the email address, and all of the rest of the email address. The
   * intervening letters are replaced with '*'.
   *
   * @param string $email
   *   The email address to mask.
   *
   * @return string
   *   Returns the masked email address.
   */
  private function maskEmail(string $email) {
    if (empty($email) === TRUE) {
      // Missing email address.
      return '';
    }

    // Email addresses are UTF-8 strings that may include non-ASCII characters
    // in both the name and domain parts of the address. Proper string handling
    // then requires that we use the PHP mb_* functions for multi-byte strings.
    //
    // Split the address into name and domain parts.
    $parts = mb_split('@', $email);
    if (count($parts) !== 2) {
      // Malformed email address either has no '@' or too many.
      // Masking is not defined in this case, so return nothing.
      return '';
    }

    // Create a masked name with the original first and last characters,
    // and the rest replaced with '*'.
    $masked = mb_substr($email, 0, 1);
    $len = mb_strlen($parts[0]) - 2;
    for ($i = 0; $i < $len; $i++) {
      $masked .= '*';
    }
    $masked .= mb_substr($email, $len + 1, 1);

    return $masked . '@' . $parts[1];
  }

}

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

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