web-dev-qa-db-ja.com

ユーザーがアカウントページでオンライン、アイドル、オフラインのいずれであるかを表示しますか?

アカウントページにユーザーのステータスを表示したい。使用しているテーマに次のコードを追加しました。機能しますが、ユーザーがオフラインで表示されることはありません。

どうして?コードの何が問題になっていますか?

user.html.twig

<div class="bs-field-status">
  {% if status == 'Online' %}
    <i class="user-online fa fa-circle fa-lg"></i> Online
  {% elseif status == 'Absent' %}
    <i class="user-absent fa fa-circle fa-lg"></i> Absent
  {% else %}
    <i class="user-offline fa fa-circle fa-lg"></i> Offline
  {% endif %}
</div>

bootstrap_subtheme_front_office.theme

<?php
/**
 * @file
 * Bootstrap sub-theme.
 *
 * Place your custom PHP code in this file.
 */

use Drupal\Core\Database\Database;

/**
 * Implements hook_entity_presave().
 */
function bootstrap_subtheme_front_office_preprocess_user(&$variables) {
  // get user object
  $user = $variables['elements']['#user'];
  //- The user has logged in at least once
  if ($user->getLastLoginTime()) {
    if (account_is_logged_in_less_then_thirty_minutes($user->id())) {
      $status = 'Online';
    }
    else {
      $status = 'Absent';
    }
  }
  else {
    $status = 'Offline';
  }
  $variables['status'] = $status;
}

/**
 * @param $uid
 *
 * @return bool
 */
function account_is_logged_in_less_then_thirty_minutes($uid) {
  $connection = Database::getConnection();
  $query = $connection->select('sessions', 'sessions')
    ->fields('sessions', ['sid', 'uid', 'timestamp'])
    ->condition('sessions.uid', $uid, '=')
    //- chef if the user was online in 30 minutes (60 * 30)
    ->condition('sessions.timestamp', \Drupal::time()
        ->getRequestTime() - (60 * 30), '>')
    ->execute();
  //- Get result.
  $results = $query->fetchAll(\PDO::FETCH_OBJ);
  return (count($results) > 0) ? TRUE : FALSE;
}
2
user91071

まず、問題はここにあると思います。

_//- The user has logged in at least once
  if ($user->getLastLoginTime()) {
    if (account_is_logged_in_less_then_thirty_minutes($user->id())) {
      $status = 'Online';
    }
    else {
      $status = 'Absent';
    }
  }
  else {
    $status = 'Offline';
  }
_

if ($user->getLastLoginTime()) {は、ユーザーが一度ログインした後は常にTRUEになります。これにより、elseがヒットすることが防止されるため、「オフライン」が設定されることはありません。

「不在」と「オフライン」の時間の違いはわかりませんが、ステータスを何に設定するかを知るために、ここで別の計算を考えたいと思います。

これは次のように簡略化できます。

_function bootstrap_subtheme_front_office_preprocess_user(&$variables) {
  // get user object
 $user = $variables['elements']['#user'];

 $last = $user->getLastAccessedTime();
 $now = \Drupal::time()->getRequestTime();

 switch ($last) {
   case ($last > ($now - 900)) :
     $variables['status'] = 'Online';
     break;
   case (($last < ($now - 900)) && $last > ($now - 1800)) :
     $variables['status'] = 'Absent';
     break;
   default:
     $variables['status'] = 'Offline';
     break;
 }
}
_

次に、小さい関数を分解して、何分前にアクティブであったかを評価します。上のスイッチでそれを使用します。

getLastAccessedTime()は:

アカウントが最後にサイトにアクセスしたときのタイムスタンプ。

値0は、ユーザーがサイトにアクセスしたことがないことを意味します。

したがって、_db_select_は必要ありません。

1
Kevin

Drupalおよびユーザーのステータスに関する最終的な問題はキャッシュですが、ここで私が作業しているコードがあります。

if ($variables['accessTime'] > (intval(time()) - 800)) {
  $variables['sessionState'] = 'active';
}
else {
  $variables['sessionState'] = 'inactive';
}

次にTwigで次のようなことができます:

{% if sessionState == active %}

{% endif %}

または

{%
  set activeClass = [
    sessionState == 'active' ? 'Active' : 'Not Active'
  ]
%}
1
Prestosaurus

彼らの答えのプレストサウルスがすでに言ったように、ここで最大の問題はキャッシュです。プリプロセスフックで行われた内容は、次回Drupalのテーマキャッシュをフラッシュするまでキャッシュされます。マークアップの最大有効期間を減らすか、完全にajax化することにより、キャッシュが確実に破壊されるようにする必要があります。


作成した ユーザーオンラインステータス 。このモジュールには、ユーザーエンティティの新しい疑似フィールド、特定のユーザーのオンラインステータスをキャッシュされていないJSON応答として返すルート、その応答をチェックしてオンラインステータスを疑似フィールドに出力するJSが含まれています。

ただし、適切な説明、スクリーンショット、テストが必要です。

  1. モジュールをダウンロードして有効にします。
  2. http://d8.localhost/user/1 に移動して、ユーザー1のオンラインステータスを確認します。

オプション: http://d8.localhost/admin/config/people/accounts/display に移動して、「オンラインステータス」フィールドの重みを調整します。


switchスニペットのクレジットをKevin( answer )に。

1
leymannx