[ViewsOnline] Статистика кто онлайн для страницы


Задался таким вопросом в связи с необходимостью вывести следующую надпись для форума:
Читают тему гостей 15, пользователей 2 (user1, user5)

В итоге родился небольшой сниппет на базе таблицы просмотров от Tickets.

Для работы скрипту нужны:
  1. установленный pdoTools
  2. включённый Fenom в настройках pdoTools
  3. установленный Tickets
  4. разрешён в настройках Tickets подсчёт просмотров гостями
Эти дополнения бесплатны и на их базе работает сниппет view_online:


<?php
// подключаем pdoTools для работы INLINE чанков 
if (file_exists(MODX_CORE_PATH . 'components/pdotools')) {$pdoTools = $modx->getService('pdoTools');}

// все возможные параметры для сниппета
if (!empty($tpl)) {$tpl = $scriptProperties['tpl'];} else {$tpl = '@INLINE Читают тему {$guests|declension:\'гость|гостя|гостей\':true}, {$users|declension:\'пользователь|пользователя|пользователей\':true}{if $users} ({$userlist}){/if}';}
if (!empty($tpl_userlist)) {$tpl_userlist = $scriptProperties['tpl_userlist'];} else {$tpl_userlist = '@INLINE {$separator}{$user|user:\'fullname\'}';}
if (!empty($pid)) {$pid = $scriptProperties['pid'];} else {$pid = $modx->resource->id;}
if (!empty($separator)) {$separator = $scriptProperties['separator'];} else {$separator = ', ';}
if (!empty($min)) {$min = $scriptProperties['min'];} else {$min = 15;}
$min = date('Y-m-d H:i:s', strtotime("-15 min") );

$output = "";

// Выборка просмотров за последние 15 минут
$q = $modx->prepare("SELECT * FROM modx_tickets_views WHERE parent = '{$pid}' AND timestamp > '{$min}' ORDER BY timestamp DESC");
$q->execute();
$r = $q->fetchAll(PDO::FETCH_ASSOC);

$users = $arr = array();
$arr['total'] = count($r);
$arr['guests'] = $arr['users'] = $i = 0;
$arr['userlist'] = '';

foreach($r as $row){
    $i++;
    if($row['uid'] > 0) {
        if($id > 1) {$userslist['separator'] = $separator;}
        $userslist[] = $row['uid'];
        $arr['userlist'] .= $pdoTools->getChunk($tpl_userlist, $userslist); // список пользователей
        $arr['users']++;
    } else {
        $arr['guests']++;
    }
}

return $pdoTools->getChunk($tpl, $arr);

Параметры сниппета

  • tpl — чанк для вывода информации, активно используются возможности Fenom. Плейсхолдеры чанка: total, guests, users и userlist. По умолчанию:
    @INLINE Читают тему {$guests|declension:\'гость|гостя|гостей\':true}, {$users|declension:\'пользователь|пользователя|пользователей\':true}{if $users} ({$userlist}){/if}
  • tpl_userlist — чанк для вывода списка пользователей, принимает 2 плейсхолдера: separator и user. По умолчанию:
    @INLINE {$separator}{$user|user:\'fullname\'}
  • separator — разделитель для списка пользователей. По умолчанию: ', '
  • pidот page id, id страницы для вывода статистики. По умолчанию текущая
  • minот minutes, количество минут, в течении которых пользователь считается на сайте. По умолчанию: 15

Теперь вызываем сниппет некэшируемым на нужной нам странице:
{'!view_online'|snippet}

Пример вызова статистики для какой-то другой страницы:
{'!view_online'|snippet: [
    'pid' => 1,
]}

Вот и всё! Всю работу за нас делают pdoTols и Tickets (за что не забываем денно и ношно благодарить Василия), а наш сниппет-надстройка просто выводит и правильно структурирует нужную нам информацию. Поэтому и не думаю что есть смысл его оформлять отдельным пакетом для репозитория.

***

UPD. Переписал весь код и собрал всё это дело в пакет. Теперь сниппет называется ViewsOnline! Появились чанки, новые параметры, исправлены ошибки. (подробнее смотри в changlog)

08 сентября 2016, 20:24    Василий Столейков   G+  
10    668 +10

Комментарии (22)

  1. Евгений 08 сентября 2016, 20:40 # 0
    Только с тикетсом работает? Или можно и к любой странице прикрутить, если вообще не установлен тикетс?
    1. Василий Столейков 08 сентября 2016, 20:43 # +1
      Работает с любой страницей, но тикетс должен быть установлен. То есть тикетс подсчитывает статистику для всех страниц сайта.
    2. Роман Садоян 08 сентября 2016, 21:53 # +1
      Поэтому и не думаю что есть смысл его оформлять отдельным пакетом для репозитория.
      Не помешало бы.
      $q = $modx->prepare("SELECT * FROM modx_tickets_views WHERE parent = '{$pid}' AND timestamp > '{$min}' ORDER BY timestamp DESC");
      Нужно заметочку, что бы не забыли изменить префикс у кого он не modx

      А в целом, Василий, благодарю хорошая работа, дал в репу!
      1. Василий Столейков 08 сентября 2016, 22:12 # 0
        Ок, спасибо, попробую. Это будет мой первый опыт оформления в репозиторий. Спасибо за заметку про префикс.
        1. Иван Климчук 09 сентября 2016, 09:57 # 0
          Нужно таки намутить отдельный репозиторий для сниппетов :) А то если честно, код сборки пакета будет больше, чем сам сниппет.
          1. Сергей Шлоков 09 сентября 2016, 10:07 # 0
            Этот репозиторий есть — готовые решения. ;) Плохо тегов тут нет.
            1. Иван Климчук 09 сентября 2016, 10:21 # +1
              С этим согласен, но тут они обычно в виде заметок, не всегда удобно выдирать код из заметки или искать линки.
              1. Василий Столейков 09 сентября 2016, 10:37 # 0
                Поэтому и оформил в пакет и выложил ссылку. Действий гораздо меньше — установил и не паришь себе мозги с копипастами всякими… ))
                1. Сергей Шлоков 09 сентября 2016, 10:42 # 0
                  Как раз наоборот. Посчитай количество шагов в том и другом случае. Лично я не стал бы ставить пакет ради одного сниппета. Тем более обновлений не планируется.
              2. Василий Столейков 09 сентября 2016, 10:33 # 0
                Выложил ссылку на пакет сюда, в репозиторий «готовые решения» ;)
                1. Василий Столейков 09 сентября 2016, 10:40 # 0
                  Т.к. это уже не просто сниппет, а и пакет, перенёс топик в «Новые дополнения и их версии».
                2. Василий Столейков 09 сентября 2016, 10:07 # 0
                  )))
              3. Сергей Шлоков 09 сентября 2016, 08:18 # +1
                Хорошее решение. Только лучше таблицу напрямую не указывать. MODX сам умеет определять
                SELECT * FROM {$modx->getTableName('TicketView')} WHERE ....
                
                1. Иван Климчук 09 сентября 2016, 09:58 # +1
                  Плюсую, как выше заметили, это так же решает проблему отличного от modx префикса.
                  1. Василий Столейков 09 сентября 2016, 10:32 # 0
                    Да, спасибо, я уже решил эту проблему и переписал весь сниппет под пакет…
                    Там много изменений в параметрах, их названиях и в названии самого сниппета. Посмотрим как отреагирует магазин и примет ли его…
                2. Василий Столейков 09 сентября 2016, 10:33 # 0
                  Обновил статью, выложил транспортный пакет и демо для просмотра работы
                  1. Алексей Андреев 26 января 2017, 13:49 # 0
                    Почему-то на части страниц выводит примерно как нужно, а на части вылезает просто код.
                    Нормально показывает там, где есть вызов getTickets и почему-то еще AjaxForm (FormIt). При этом на всех страницах есть вызов TicketLatest.



                    И при parents=0 всё равно считает посетителей для каждой страницы, а я хотел показать сколько всего в данный момент на сайте гостей и юзеров.
                    1. Василий Столейков 26 января 2017, 13:55 # 0
                      А в логи что-то пишется?
                      1. Алексей Андреев 26 января 2017, 13:58 # 0
                        [2017-01-26 11:02:37] (ERROR @ /web/core/components/pdotools/model/pdotools/pdotools.class.php : 940) Unexpected tag 'display' in 4e4426b62082931c8782625cb4787966 line 114, near '{display:' <- there
                        Не знаю, относится это к делу или нет, но похоже. pdoTools свежий.
                        1. Василий Столейков 26 января 2017, 14:20 # 0
                          Сбился веткой, ответил чуть ниже.
                    2. Василий Столейков 26 января 2017, 14:05 # +1
                      Нет, это похоже на конфликт фенома с javascript на странице. Найди в коде страницы {display: и добавь пробел после фигурной скобки вот так { display:.
                      Этот конфликт и мешает запуску сниппета на тех неработающих страницах. Именно там и ищи.
                      1. Алексей Андреев 26 января 2017, 14:23 # 0
                        И правда, сработало =) спасибо
                        А что делать с parents=0?
                      Вы должны авторизоваться, чтобы оставлять комментарии.