Версия: 5.x
Работа со счетчиками

В ReadyScript 3.0 были добавлены классы для работы с внутренними счетчиками. Счетчики должны показывать администратору кличество непросмотренных объектов. Например, кол-во непросмотренных заказов, покупок в 1 клик, предварительных заказов, комментариев и т.д.

Рассмотрим, как работает подсистема счетчиков и не происходит лишней нагрузки на время генерации страницы.

  1. При открытии страницы, в JS переменной global.meterNextRecalculation записывается время, через которое следует обновить счетчики.
  2. На стороне административной панели, в скрипте jquery.rs.admin.js инициализируется модуль jQuery.rsMeters, который через указанное в global.meterNextRecalculation время выолняет запрос на global.meterRecalculationUrl с ожиданием получить JSON с данными по счетчикам. Если в global.meterNextRecalculation будет 0, это будет означать, что запрос на получение счетчиков будет выполнен сразу после открытия страницы административной панели в отдельном потоке. Интервал между пересчетами задается в административной панели в разделе Управление → Настройка системы.
  3. В момент запроса на сервер к global.meterRecalculationUrl, на сервере происходит событие meter.recalculate. Любой модуль сожет его перехватить и предоставить сведения по своим счетчикам.
  4. Далее rsMeters скрипт парсит полученный JSON, получает идентификаторы и связанными с ними цифрами, затем пробегается по DOM дереву и обновляет заранее установленные метки, в которых должны быть вписаны счетчики.
  5. Последний результат получения счетчиков кэшируется на стороне сервера с помощью класса Main::Model::NoticeSystem::Meter, поэтому при обновлении страницы или переходе между страницами пересчета не происходит, счетчики отображаются из кэша. Фактически, пересчет может происходить только из AJAX-запроса.
Заметки
Счетчики могут рассчитываться в рамках, текущего сайта, пользователя, объекта. Соответственно у разных администраторов счетчики могут показывать независимую информацию.

Как добавить подсчет непросмотренных объектов в свой модуль?

Рассмотрим кейс. У вас есть модуль предоставляющий возможность писать комментарии к товару. Как сделать, чтобы число непросмотренных комментариев отображалось в административной панели в меню и на странице со списком комментариев? Очевидно, что пункт меню, как минимум должен добавляться вашим модулем в систему, чтобы возле него можно было отобразить счетчик. Напомним, что добавить пункт меню можно обработав событие getmenus.

Итак, начнем с отображения флажка "непрочитано" в списке комментариев.

readed_flag.png
Флаг просмотра объекта

Для начала нам нужно подготовить специальное API, которое сможет выполнять следующие действия:

  • возвращение идентификатора счетчика,
  • возвращает количество непросмотренных объектов
  • установка отметки о просмотре одного объекта
  • установка отметки о просмотре всех объектов
  • удаление отметки о просмотре объекта

Все эти действия мы описали в интерфейсе Main::Model::NoticeSystem::MeterApiInterface в соответствующих методах:

Для самого распространенного случая, когда счетчик должен подсчитывать количество непросмотренных ORM-объектов одного типа, мы подготовили готовый класс Main::Model::NoticeSystem::MeterApi. Чтобы получить доступ к вышеперечисленным действиям, в конструктор данного класса достаточно передать следующие аргументы:

  • $orm_object - объект класса RS::Orm::AbstractObject,
  • $meter_id - Строковый идентификатор счетчика,
  • $site_id - Идентификатор сайта или null, чтобы использовать текущий сайт
  • $user_id - Идентификатор текущего пользователя или null, чтобы использовать текущего пользователя

Пример:

$meter_api = new \Main\Model\NoticeSystem\MeterApi(new \Comments\Model\Orm\Comment, 'rs-admin-menu-comments', null, null);
//Вернет количество непросмотренных объектов
echo $meter_api->getUnviewedCounter();

Далее, если вы желаете, чтобы в CRUD контроллере была возможность просмотра красных флажков о непросмотренных объектах и установки флага просмотра того или иного объекта, нужно подсказать системе, что наша модель Comments::Model::Api умеет работать со счетчиками.

Для этого в классе Comments::Model::Api нужно имплементировать интерфейс Main::Model::NoticeSystem::HasMeterInterface. Интерфейс описывает следующие методы:

<?php
/**
* Интерфейс сообщает, что класс поддерживает учет просмотров одного объекта
* и готов вернуть API для работы со счетчиками. Данный интерфейс следует применять у DAO(EntityList) классов,
* если в Crud контроллере требуется поддержка отображения просмотренных/непросмотренных объектов
*/
interface HasMeterInterface
{
/**
* Возвращает API по работе со счетчиками
*
* @return \Main\Model\NoticeSystem\MeterApiInterface
*/
function getMeterApi();
}

Имплементируем указанный интерфейс в нашей модели:

<?php
namespace Comments\Model;
implements HasMeterInterface
{
const
METER_COMMENT = 'rs-admin-menu-comments'; //Идентификатор счетчика
//...
/**
* Возвращает API для работы со счетчиками
*
* @return \Main\Model\NoticeSystem\MeterApiInterface
*/
function getMeterApi($user_id = null)
{
return new \Main\Model\NoticeSystem\MeterApi(
$this->obj_instance, //Передаем ORM объект, с которым работает модель \Comments\Model\Orm\Comment
self::METER_COMMENT, //Сообщаем идентификатор счетчика
$this->getSiteContext(), //Сообщаем тот ID сайта, с которым работает модель
$user_id);
}
//...
}

Таким образом, мы сообщили CRUD контроллеру, что наша модель поддерживает работу со счетчиками, соответственно стали доступны действия actionMarkOneAsViewed (отметить один объект просмотренным), actionMarkAllAsViewed (отметить все объекты просмотренными), при выполнении действия actionEdit - объект также будет отмечен просмотренным.

Далее нужно добавить в таблицу специальную колонку, которая будет содержать нужный нам флажок, для этого корректируем административный CRUD контроллер:

<?php
use \RS\Html\Table\Type as TableType,
\RS\Html\Table;
class Ctrl extends \RS\Controller\Admin\Crud
{
protected
/**
* @var \Comments\Model\Api
*/
function __construct()
{
parent::__construct(new \Comments\Model\Api());
}
function helperIndex()
{
$helper = parent::helperIndex();
$helper->setTopHelp(t('Здесь отображаются комментарии ко всем объектам на сайте, для которых доступно комментирование. Воспользуйтесь фильтром, чтобы отобрать комментарии к нужному объекту. В настройках модуля можно установить, необходимо ли премодерировать комментарии, возможно ли написать более одного комментария к одному объекту с одного IP, а также другие настройки.'));
$helper->setTopTitle(t('Комментарии'));
$helper->setTable(new Table\Element(array(
'Columns' => array(
new TableType\Checkbox('id'),
//Создаем колонку, которая будет отображать текущий статус просмотра объекта,
//а также позволит изменять его.
new TableType\Viewed(null, $this->api->getMeterApi()),
//...
))));
//...
}
//...
}

Далее привяжем пересчет счетчиков к общему событию meter.recalculate, чтобы находясь в административной панели на любой странице у вас периодически обновлялся ваш счетчик.

Класс с обработчиками событий может выглядеть так:

<?php
namespace Comments\Config;
use Comments\Model\Api as CommentsApi;
class Handlers extends \RS\Event\HandlerAbstract
{
function init()
{
$this
->bind('getmenus')
->bind('meter.recalculate');
}
/**
* Возвращает пункты меню этого модуля в виде массива
*
*/
public static function getMenus($items)
{
$items[] = array(
'title' => t('Комментарии'),
'alias' => 'comments', //Этот идентификатор повлиял на идентиикатор $meter_id, к нему вначале приписывается rs-admin-menu-
'link' => '%ADMINPATH%/comments-ctrl/',
'typelink' => 'link',
'parent' => 'modules'
);
return $items;
}
/**
* Добавляем информацию о количестве непросмотренных заказов
* во время вызова события пересчета счетчиков
*/
public static function meterRecalculate($meters)
{
$comment_api = new CommentsApi();
$comment_meter_api = $comment_api->getMeterApi();
//Добавляет в список информацию о непросмотренных сообщениях
$meters[$comment_meter_api->getMeterId()] = $comment_meter_api->getUnviewedCounter();
return $meters;
}
}