Взаимодействие модуля с ядром системы

Создание модуля Комментариев нет

Введение

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

Взаимодействие с объектами

Объектная модель данных лежит в основе системы MajorDoMo и большинство модулей так или иначе взаимодействуют с объектами системы. Например, все модули работы с аппаратными протоколами “привязываются” к объектам для того, чтобы сохранить в их свойствах данные от оборудования, либо для отправки управляющих команд оборудованию. В обоих случаях используется такое понятие как “связанный объект/свойство”, т.е. к некой сущности оборудования привязывается объект (и свойство), которое должно отражать текущее состояние оборудование (например, значение датчика температуры), либо которое должно быть управляющим сигналом для изменение состояния оборудования (например, переключать состояние реле при изменении значения свойства связанного объекта).

Для сохранения данных в связанный объект (связь типа “модуль>свойство”) в модуле создается таблица привязки физических данных к объекту и соответствующий интерфейс выбора этого самого связанного объекта и свойства.

Пример интерфейса настройки:

Алгоритм работы модуля в таком случае таков:

  1. Модуль получает информацию от физического устройства
  2. Смотрит есть ли запись о связанном объекте для данной сущности
  3. Записывает полученное от устройства значение в связанный объект и свойство.

В некоторых случаях также имеет смысл вместе с сохранением данных в свойстве запустить ещё какой-то метод объекта и тогда в интерфейсе связи появляется дополнительное поле “Связанный метод”, вызов которого происходит после сохранения данных в свойстве.

Типовой пример кода модуля при получении информации от устройства:

Способ получения информации от устройства полностью реализуется самим модулем.

Кроме передачи данных в связанный объект/свойства, зачастую возникает необходимость обработки изменения значения связанного свойства. Для этого ядро системы должно понимать, что при любом изменении свойства необходимо обратиться к соответствующую модулю для обработки данного события. Связь “свойство>модуль” реализуется путём вызова в коде модуля функции addLinkedProperty при работе с интерфейсом настройки связей.

Пример вызова функции:

Если указанная связь установлена, то алгоритм реакции на изменение свойства будет следующим:

  1. Ядро видит, что с изменяемым свойством связан модуль $module_name
  2. Ядро активирует функцию вызова метода propertySetHandle($object, $property, $value) для экземпляра модуля $module_name с передачей ему имени объекта, свойства и нового значения

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

Пример реализации указанного метода внутри класса модуля:

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

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

В ядре системы существует модель инициирования и реакции на события. Данные события не связаны с изменениями свойств объектов, но могут быть обработаны модулями, которые подписаны на получение уведомлений на определённые события. Примером такого события может быть команда пользователя -- голосовая или текстовая. У события всегда есть его системное имя (например, COMMAND) и (опционально) детали события (ассоциативный массив).

Для подписки на событие модуль должен вызвать функцию subscribeToEvent($module_name, $event_name). Обычно данная функция вызывается в методе install() класса модуля.

Пример вызова:

События инициируются функцией processSubscriptions($event_name, $params) (либо аналогичной функцией processSubscriptionsSafe).

Пример инициализации события:

При инициализации события ядро системы смотрит всех подписчиков события и запускает методы processSubsription($event_name, $details) у всех модулей, подписанных на событие. Таким образом, в классе модуля должен быть задан соответствующий метод и код обработки события.

Для отписки от события можно использовать функцию unsubscribeFromEvent($module_name, $event_name = '')

Основные события, формирующиеся в системе:

Ещё один аспект применения событий -- встраивание собственого HTML-кода в места “горячей вставки” в шаблонах. С помощью специальной разметки в шаблон можно добавить такие места. Например, в шаблоне /templates/panel_default.html есть такая конструкция:

Она означает, что на данном месте будет вставлен код, возвращаемый обработчиками события panelHomeColumnLeft. Таким образом, любой модуль может подписаться на это событие командой subscribeToEvent($this->name, 'panelHomeColumnLeft'); а обработчик может иметь следующий вид:

Соответственно, при формировании страницы на месте приведённого комментария будет выведен текст Hello

Создание собственных классов/объектов/свойств

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

addClass($class_name, $parent_class = '') -- добавление нового класса с именем $class_name и возможность сделать его дочерним по отношению к классу с именем $parent_class (опционально)

addClassMethod($class_name, $method_name, $code = '', $key = '') -- добавление к классу $class_name метода с названием $method_name и кодом метода $code. В случае указания ключа $key в код класса будет создана “инъекция” с соответствующим ключем (см. ниже).

addClassProperty($class_name, $property_name, $keep_history = 0) -- добавление к классу $class_name свойства $property_name с возможностью указать количество дней $keep_history для хранения истории изменения свойства

addClassObject($class_name, $object_name, $system = '') -- добавление объекта класса $class_name под названием $objct_name с возможностью указать системное имя объекта $system (использование системного имени позволяет позже обратиться к конкретному объекту даже если пользователь изменит его наименование)

Инъекция кода

Инъекция кода представляет собой механизм вставки собственного кода в метод существующего объекта. Делается это с помощью функции:

Где $method_name -- имя вида “объект.метод”, $key -- ключ инъекции, $code -- код для вставки.

Ключ инъекции используется для того, чтобы повторный вызов данной функции не добавлял дополнительную копию вставляемого кода, а заменял существующий блок, если он был добавлен ранее.

Пример вызова инъекции:

Виджеты для дашборда

Любой модуль системы может предоставить свой набор виджетов для использования его в интерфейсе типа “Дашборд”. Для этого в папке модуля должен быть создан файл вида <module_name>_widgets.js.php (например /modules/commands/commands_widgets.js.php). Структура и код файла должен соответствовать системе создания виджетов для проекта Freeboard.

Поделитесь в соц сетях

Теги: