Посты / Как узнать, что пользователь находится в Online? Простая идея для Laravel 5.4

24.02.2017 17:35
Привет, друзья. Хочу поделиться простой идеей, как можно определить, находится ли сейчас пользователь в Online или нет. Решение, в принципе, подходит для последних версий Ларавел. Но пример создавался на Ларавел 5.4 версии

Итак, как это вообще можно сделать, чисто теоретически? Вариантов, на самом деле, много. Но мне нравится один вариант, основная идея которого состоит в том, чтобы положить некоторые данные о пользователе в кэш на пять минут. А потом проверять их, есть ли такие данные в кэше. Если есть, то пользователь все еще в онлайн, если нет, то пользователь покинул сайт.

Итак, приступим к реализации. Для этого нам придется создать свой посредник (middleware) в котором мы будем записывать данные в кэш. Создадим его:

php artisan make:middleware IsUserOnline
В папке App/Http/Middleware появится новый файл IsUserOnline.php

Откроем его и допишем свой код:
<?php
/**
* Check user online.
*/

namespace App\Http\Middleware;

use Closure;
use Auth;
use Carbon\Carbon;
use Cache;

class IsUserOnline
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
// If user logged then create cache data on the 5 minutes.
if (Auth::check()) {
$user = Auth::user();

$expiresAt = Carbon::now()->addMinutes(5);
Cache::put('user-is-online-' . $user->id, true, $expiresAt);

}

return $next($request);
}
}
В метод мы ставим проверку того, является ли пользователь авторизованным. Если является, тогда мы получаем инстанс этого пользователя. Далее мы создаем новую дату для хранения кэша:
$expiresAt = Carbon::now()->addMinutes(5);
Это означает, что мы берем дату, которая сейчас, и прибавляем к ней пять минут. Для удобной работы с датами есть очень удобный функционал Carbon.

После этого, мы помещаем в кэш данные, в виде ключ - значение. В виде ключа выступает идентификатор пользователя дописанный к строке:
'user-is-online-' . $user->id
Так нам будет легче и понятнее получать запись из кэша. Вторым параметром идет булево значение - истина. Но это не суть важно, так как мы будем проверять именно наличие данной записи в кэше. Третий параметр - это дата, когда истечет валидность этой кэш записи. В данном конкретном случае, через пять минут запись будет удалена из кэша автоматически.

С посредником закончили, теперь нам нужно его подключить, чтобы он все время вызывался при каждом запросе. Для этого перейдем к файлу App/Http/Kernel.php и добавим наш посредник в группу к другим посредникам:
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\IsUserOnline::class, // Наш посредник.

],

'api' => [
'throttle:60,1',
'bindings',
],
];
Все, теперь наш посредник будет работать при каждом запросе. Дальше нам нужно создать свой метод, в модели User. Кто-то посчитает такой подход не самым лучшим, но лично я, ничего смертельного в этом не вижу. Итак, дописываем в модель пользователя новый метод:
/**
* Check is user online.
* @return bool
*/
public function isOnline()
{
return Cache::has('user-is-online-' . $this->id);
}
Мы просто проверяем, есть ли для вызванного пользователя запись в кэше. Если есть, вернем истина, если нет, то ложь. Больше ничего дописывать не нужно. Атрибут $this->id вам даст идентификатор пользователя, к которому вы будете обращаться. С моделью все.

Дальше остался простой штрих. Вы можете прямо из вашего шаблона вызвать метод проверки пользователя в онлайн, например так:
@if($user->isOnline())
<span class="color-green font-size-12"><i class="demo-icon icon-circle"></i>
{{ trans('interface.Online') }}</span>
@else
<span class="color-red font-size-12"><i class="demo-icon icon-circle-empty"></i>
{{ trans('interface.Offline') }}</span>
@endif
Здесь все просто. Мы вызываем метод через инстанс пользователя:
$user->isOnline()
Если он нам вернет истину, то покажем иконку заполненного зеленного кружочка и напишем текст Online. Если ложь, тогда покажем красный пустой кружок и напишем текст Offline.

Идея позаимствована от сюда: https://erikbelusic.com/tracking-if-a-user-is-online-in-laravel/ 

Вот и все! Очень просто и легко. Жду ваших замечаний в комментариях. Всем успехов и до новой встречи.

1

Комментарии (20):

Когда-то эту идею я позаимствовал на просторах интернета. Саму идею! В статье я написал:
Но мне нравится один вариант, основная идея которого состоит в том, чтобы положить некоторые данные о пользователе в кэш на пять минут.
Я ведь не написал, что я придумал ее! Статью сам написал. Не перевод! Сообщество мне кинуло ссылку на источник, и я ее вставил в статью.

очень-очень похоже на вашу статью https://erikbelusic.com/tracking-if-a-user-is-online-in-laravel/
Перевод или так совпало?

Alexander писал(а):
Да, но для этого достаточно в .env заменить file na session :)
Да, надо. И для статьи это нужно указать, чтобы новичок не был в ступоре.
Да, но для этого достаточно в .env заменить file na session :)
Alexander писал(а):
http://joxi.ru/zANpZyjuB13GKm
Так получается, что не автоматически пишет, а надо установить на базу данных будет.
Kirill wrote:
'driver' => env('SESSION_DRIVER', 'file'),
Это значит где будет хранится сессия - файл, база данных или еще где-то
Alexander писал(а):
В том и фишка, что не нужно, ларавел сам пишет, при условии что вы используете стандартную модель User
А что значит эта запись в конфиге:
'driver' => env('SESSION_DRIVER', 'file'),
Kirill wrote:
Прикол. Это во всех версиях так было или в последних?
Я юзал в 5.2 по-мойму, было ли раньше не скажу
Kirill wrote:
Да, и еще момент. Сколько живет ваша сессия? И будете ли вы считать, что пользователь в онлайн, если он два часа не заходит на страницу, но вкладка в браузере висит открытой? Ответить с цитатой
Там записывается время последней активности, в вашей ситуации, там будет записано время двух часовой давности
Alexander писал(а):
В том и фишка, что не нужно, ларавел сам пишет, при условии что вы используете стандартную модель User
Прикол. Это во всех версиях так было или в последних?
Kirill wrote:
Настройки-то нужно прописать, чтобы в таблицу писал.
В том и фишка, что не нужно, ларавел сам пишет, при условии что вы используете стандартную модель User
Да, и еще момент. Сколько живет ваша сессия? И будете ли вы считать, что пользователь в онлайн, если он два часа не заходит на страницу, но вкладка в браузере висит открытой?
Alexander писал(а):
Все, дальше ларавел сам записывает туда , активность пользователя
Настройки-то нужно прописать, чтобы в таблицу писал.
В данном случае да. Эта  таблица создается двумя командами, которые копируются из доки
php artisan session:table
 php artisan migrate
Все, дальше ларавел сам записывает туда , активность пользователя
Alexander писал(а):
public function getOnlineAttribute() { $activity = DB::table('sessions')->where('user_id',$this->id)->where('last_activity','>',strtotime("-15 minutes"))->count(); return $activity ? 'Online' : 'Offline' ; }
Эээ, вы считаете, что создать таблицу в базе и получать запросы проще и быстрее? Плюс не забываем, что данные в таблице тоже нужно положить.
Согласен, что вариантов решения много, просто по сути это уже сделано в Ларавеле.
Достаточно сделать миграцию , и в модели юзера добавить что то такое

public function getOnlineAttribute() {
 $activity = DB::table('sessions')->where('user_id',$this->id)->where('last_activity','>',strtotime("-15 minutes"))->count();
 return $activity ? 'Online' : 'Offline' ;
 }

И тогда получить статус онлайна юзера можно так $user->Online
Alexander писал(а):
Ознакомтесь https://laravel.com/docs/5.4/session
Я знаком с сессиями, и очень неплохо. Но я ведь написал в статье:
Вариантов, на самом деле, много. Но мне нравится один вариант, основная идея которого состоит в том, чтобы положить некоторые данные о пользователе в кэш на пять минут.
Вы можете написать свою статью, как узнать о пользователе в онлайн, через сессию, и я ее здесь с удовольствием опубликую!

В частности http://joxi.ru/ZrJOWN0I9QKx1m 
Плохо что у вас нельзя редактировать комментарии.

Ознакомтесь https://laravel.com/docs/5.4/session