META
Руководства
Отслеживание изменений сущностей

Отслеживание изменений сущностей

Для отслеживания изменений сущности существует механизм подписки (listen), который, в зависимости от своих параметров, использует одну из двух реализаций:

  • Подписка на события изменения сущности (ADD, SET, REMOVE)
  • Подписка на канал событий, связанных с сущностями

Подписка на события изменения сущности

Реализация этого механизма предполагает уведомление фронтенда об изменениях сущности через ответ сервера, который будет доступен только на той странице, на которой был сделан запрос к бэкенду. Все примеры, перечисленные ниже, относятся как раз к этой ситуации.

Например, если при сохранении формы в модальном окне нужно обновить инпуты в родительской форме или обновить список объектов сущности, если вы изменили или добавили новую.

Случай 1

Бывают случаи, когда у вас есть форма создания/редактирования объекта и в ней есть инпут с выбором объекта другого типа. Например: вы добавляете товар и выбираете его категорию, а если категории нет, то вы хотите прямо здесь ее создать.

В этом случае у инпута выбора категории нужно добавить кнопку создания объекта через "addObjectButton" и добавить прослушку событий по объектам указаного типа через "listen" чтобы после создания объект появлвлся в выпадающем списке.

На форме, где у вас будет инпут обязательно добавьте секции:

  • attrs.addObjectButton
  • listen
{
  "id": "mylego",
  "name": "me-lego",
  "elems": [
    {
      "id": "ex_access_id",
      "name": "me-input",
      "entityId": 2830,
      "attrs": {
        "type": "select", // говорим, что  у нас выпадающий селектбокс
        "required": true,
        "addObjectButton": { // говорим, что у нас есть кнопка создания объектов указанного entity_id
          "env": {
            "sp": { // если вам нужно перезать что-то на страницу создания объекта, при нажатии на кнопку создания объекта сделайте это тут
              "obj": {
                "mode": "feed",
                "ex_system_id": "google_adwords"
              }
            }
          },
          "title": "Подключить аккаунт"
        }
      },
      "listen": [
        {
         // Тут мы гвоорим, что хотим отслеживать изменения сущности при операция добавление и изменения
          "code": [
            "ADD",
            "SET"
          ],
          "entityId": 2830,
          "refreshRefPvmData": {},  // Говорим, что хотим обновлять список опшенов me-input
          "objectId": 0
        }
      ],
      
      // Это просто для полноценности примера
      "label": "Укажите аккаунт для получения данных или добавьте новый",
      "refPvmData": {
        "id": "$metaql",
        "sp": {
          // Кстати, это хороший пример использования защищенного языка запросов к данным. Это не полноценный SQL
          // Тут работает общий ACL и нет ничего, кроме простых SELECT запросов
          "dbQuery": {
            "command": "SELECT id,name FROM meta.ex_access WHERE ex_system_id = 'google_adwords' and user_status='ENABLED' ORDER BY name"
          }
        }
      }
    }
  ]
}

Случай 2

Или у вас есть список объектов какой-либо сущности в таблице и при редактировании или добавлении объекта в модальном окне вы хотите перезагружать данные таблицы

Для таблицы добавляется атрибут listen

  • code: укажите на какие коды вы подписываетесь ADD, SET, REMOVE
  • entityId: укажите id сущности, которую будете прослушивать
  • reload: говорит, что надо сделать reload страницы при получении уведомления об изменении данных
<script type="meta/sql" order="400" id="res" entity-id="2830" db-alias="meta" entity-id="ex_system" 
  listen='[{"code": ["ADD", "REMOVE", "SET"], "reload":{},"entityId": "2830"}]'
...

На стороне модального окна

На стороне страницы создания/редактирования объекта сущности нужно обязательно залогировать добавление или изменение вызовом ObjectLogService.logValue. Эти данные пойдут в лог и смогут быть использованы для подписки на события через артрибут listen

<script type="meta/js" elem="hidden" states="save">
function main(pvm, vm, env, ObjectLogService) {
  var isNew = false;
  var objectId = env.object_id;
  pvm.toInitialState();
  pvm.closeModal();
  pvm.changeState('default');
  pvm.popup = {level: "success", message: "${i18n('common.saveSuccess')}"};
  ObjectLogService.logValue(env.entityId, objectId, isNew ? 'ADD' : 'SET', env.sp.obj);
}
</script> 

Подписка на канал событий

Это более общий случай использования уведомлений об изменении объектов. Он позволяет обрабатывать события в других окнах браузера и реализует отправку событий через сокеты (PubSubService).

Также, именно эта реализация позволяет уведомлять об изменении объектов не только текущее, но и остальные открытые пользователем окна браузера с Метой.

Пример:

<script type="meta/sql" order="400" id="res" entity-id="2830" db-alias="meta" entity-id="ex_system" 
  listen='[{"pubSubChannel": ["ObjectLogService"], "reload":{},"entityId": "2830", "objectId": "12"}]'
...

В данном примере мы подписываемся на события в канале ObjectLogService, которые будут связаны с определенным entityId и objectId. При этом objectId - необязательный параметр, можно подписываться на события всех объектов сущности.

ObjectLogService - зарезервированный канал, используемый сервисом ObjectLogService, который, кроме отправки сообщений об изменении объектов в Шину, отправляет также пользователю, инициировавшему изменение объекта сообщение через PubSubService.

PubSubService можно также вызвать самостоятельно, например:

<script type="meta/js" elem="hidden" states="save">
function main(pvm, vm, env, PubSubService) {
  PubSubService.pubToUserChannel(env.user_id, 'page', 'c16649d7-866b-47d9-a61c-0370596cd575', 'test_channel', {});
}
</script> 

Подобный код вызвал бы срабатывание слушателя, настроенного следующим образом:

<script type="meta/sql" order="400" id="res" entity-id="2830" db-alias="meta" entity-id="ex_system" 
  listen='[{"pubSubChannel": ["test_channel"], "reload":{},"entityId": "page", "objectId": "c16649d7-866b-47d9-a61c-0370596cd575"}]'
...