Это старая версия документа.
Пошаговое осваивание фреймворка ABillS
Писалось для версии 0.77.14
В данном руководстве, Вы пошагово ознакомитесь с основными частями системы.
Фреймворк состоит из нескольких частей:
- Ядро вебинтерфейса (движок) (
index.cgi
) - Работа с БД (
dbcore.pm
) - Работа с визуализацией
- Базовые библиотеки
- Файл конфигурации
Сначала рассмотрим составные части модуля, чтобы понимать, что нужно для написания логически интегрированного функционала.
В ABillS основная часть кода написана в функциональном или процедурном стиле, что влияет на работу с системой. Кроме того, поскольку ООП не используется для полиморфизма или расширения функционала классов через наследование, многие функции принимают аргумент $attr, в котором записаны дополнительные условия выполнения (которые могут кардинально изменять как результат так и логику выполнения), поэтому нужно всегда учитывать полную сигнатуру вызова при чтении кода.
Структура модуля ABillS
Модуль ABillS (для примера Example
) состоит из:
- Класса менеджера сущностей в БД. (
Abills/mysql/Example.pm
) - Файл с логикой (функциями)
Abills/modules/Example/webinterface
- Описание меню
Abills/modules/Example/config
- Дополнительные файлы словарных переменных (необязательно) (
Abills/modules/lng_english.pl
) - Файла описания схемы БД (
db/Example.sql
)
Теперь, когда мы рассмотрели какие части должны быть в самом модуле, детально рассмотрим взаимодействие модуля с частями фреймворка.
Регистрация модуля в движке
После добавления имени модуля в массив @MODULES
(libexec/config.pl), при инициализации движка читается файл config
из папки модуля и словарь с переменными текущего языка пользователя вебинтерфейса. Функции из config
добавляются в глобальные реестр функций интерфейса, при этом каждой присваивается особый числовой индекс, который позволяет вызвать эту функцию.
Сами функции должны быть доступны в webinterface
(или быть импортированы из других пакетов внутри webinterface
)
Поскольку все webinterface
выполняются в глобальной области видимости, к имени каждой функции нужно добавлять имя модуля.
Основная часть - вебинтерфейс
В основном случае, логика вебинтерфейса проста и прозрачна - получить данные, обработать и вывести в каком-то виде (шаблон или таблица). Получить данные можно несколькими способами:
- Из БД (ссылка на работу с БД)
- Из внешнего источника (здесь ссылка на web_request)
- Из других модулей
Для примера рассмотрим работу с сущностью entity
в модуле Example
Работа с БД
Все классы работы с БД наследуются от dbcore
. В таком случае в классе становятся доступны следующие методы:
query($query, $type, $attr) | выполнение запроса к БД ( В основном используется для операции SELECT ) |
changes($table, $data, $attr) | обёртка над query(«UPDATE …»). Сравнивает данные в таблице и изменяет только поля с обновлёнными значениями. Может добавлять в системный лог записи об изменении |
query_add($table, $data, $attr) | обёртка над query(«INSERT …»). Добавляет данные в таблицу, инкапсулирует логику обработки значений некоторых типов (ip , netmask , attachment , reply , text …) |
query_del($table, $data, $extended_params, $attr) | обёртка над query(«DELETE …»), В нормальном случае используется для удаления строки с id = $data→{ID} |
search_former($search_columns, $attr) | специальный метод формирования WHERE части запроса. |
Все эти методы должны вызываться в объекте с заданными полями conf
, db
, admin
($self→{db}
, $self→{conf}
, $self→{admin}
).
Рассмотрим работу с каждым из методов детальнее.
query($query, $type, $attr)
Метод query() выполняет запрос к базе и в зависимости от аргумента $type получает результат и в зависимости от значений в $attr применяет к нему некоторые преобразования.
Рассмотрим примеры запросов и результат выполнения.
$self->query("SELECT * FROM example_entity");
Результатом выполнения будет запись в $self→{list}
двумерного масива содержимого таблицы example_entity
.
$self->query("SELECT * FROM example_entity", undef, { COLS_NAME => 1 })
Здесь в качестве $type мы указываем undef
для получения данных из базы. $attr→{COLS_NAME} ⇒ 1
говорит, что мы хотим получить результаты в виде масива хешей. Результатом выполнения будет запись в $self→{list} масива хешей, где ключами хеша будут названия столбцов таблицы, а значениями - соответственно значения.
Поскольку структура таблицы (порядок столбцов в таблице) может меняться, использование COLS_NAME
предпочтительнее (Читать как: Использовать всегда и везде при получении списков базы)
Следующий пример удобен, когда в коде нам нужно будет сформировать простой список выбора или поисковую таблицу ключ - значение. (Например, по id строки)
$self->query("SELECT id,name FROM example_entity", undef, { LIST2HASH => 'id,name' });
Результатом выполнения запроса будет запись в $self→{list_hash}
хеша, где ключ id
строки, а значение name
.
Теперь рассмотрим ключ COLS_UPPER
.
$self->query("SELECT * FROM example_entity", undef, { COLS_NAME => 1, COLS_UPPER => 1 })
Использование этого ключа связано с системой шаблонов, по утверждённому стандарту, названия столбцом таблицы указываются в lowercase, а переменные шаблона указываются в UPPERCASE. Таким образом, для передачи данных из БД в шаблон, пришлось бы вручную переназначать переменные при передаче в шаблон. Ключ COLS_UPPER
дублирует ключи в хеше в в виде UPPERCASE, что позволяет передавать строки результата в шаблон без дополнительной логики.