Описание отчётов
Введение
Панель управления имеет встроенный механизм для формирования различных отчетов. Под отчетом понимается представление статистических данных в виде списков с графиками или без них.


Дальнейшее изложение предполагает, что читатель знаком с общей структурой метаданных, по которым строится UI ispmanager, обзор ее приведен в статье “Структура и возможности плагинов”.
Если перед вами стоит задача создания нового отчета в ispmanager, то возможны два варианта ее решения:
- написать обработчик, который вернет XML-описание страницы с отчетом. Об обработчиках и приемах их написания можно прочесть по ссылке выше. В этой статье данный способ рассматривается как базовый, раздел об элементе
<reportdata>применим только при использовании этого варианта создания отчетов. - добавить метаданные отчета в XML-описание плагина и использовать элементы
<action>или<query>для получения данных. Пример кода для этого варианта приведен в конце статьи.
Ниже приведено описание структуры метаданных в формате XML, по которым строятся отчеты, а также структуры данных, передаваемых для отображения в отчетах.
Общая структура страницы отчета
- Форма: нужна для выбора периода или объекта отображаемых данных. Описывается тегом
<form>внутри элемента<metadata> - Таблица: отображает данные. Описывается тегом
<band>внутри элемента<metadata>. Таблица в отчете несколько отличается от обычного списка. У нее есть сортировка, на странице может быть более одной таблицы; ячейки таблицы могут содержать ссылки на вложенные отчеты, а также якоря на ниже расположенные отчеты.
Таблица может быть скрыта или показана с помощью специальной кнопки над таблицей. - Диаграмма: строится по данным из таблицы, описывается тегом
<diagram>внутри элемента<band>. Таким образом, диаграмма в отчете всегда привязана к какой-либо таблице.
По данным из одной таблицы может быть построено несколько диаграмм.
Элемент <band> может содержать вложенные элементы <band>, соответствующие дочерним отчетам, которые отражаются ниже “родительского” на той же странице. Предполагается, что дочерние отчеты так же, как родительский, отображают данные, соответствующие выбранным в форме параметрам отчета.
<metadata name="test.report" type="report" level="admin+" mgr="core">
<toolbar>
<toolbtn func="journal" type="back" img="t-back" name="back"/>
</toolbar>
<text name="title" />
<band name="game" psort="game_name">
<diagram name="games_chart" label="game_name" data="game_size" type="pie" />
<col name="game_name" type="data" total="count" link="yes" />
<col name="game_size" type="data" total="sumsuffix" convert="bytes" sorted="-1" />
<col name="game_price" type="data" total="sumsuffix" convert="money" sort="digit"/>
<band name="sales" psort="game_name">
<diagram name="games_per_country_chart" label="country_name" type="histogram">
<line data="sold_count" />
</diagram>
<col name="country_name" type="data" total="count" />
<col name="sold_count" type="data" sort="digit" total="sum" sorted="-1" />
</band>
</band>
</metadata>Комментарии к приведенному выше коду:
- Приведенный выше код не содержит данных для отчета, как и строк локализации, таких, как заголовок отчета, - только метаданные, описывающие структуру отчета. Данные отчета и строки локализации будут обсуждаться в последующих разделах этой статьи.
- Элемент
<toolbar>не имеет прямого отношения к отчету и выполняет ту же функцию, что в формах - содержит кнопки, которые могут выполнять различные действия. В данном случае тулбар содержит кнопку “Назад” - Элемент
<band>верхнего уровня описывает основной отчет. Таблица основного отчета содержит три столбца, описываемых элементами<col> - Вложенный элемент
<band>описывает дочерние таблицы, количество которых будет соответствовать количеству строк в таблице основного отчета - Как родительский, так и вложенный элемент
<band>содержат по элементу<diagram>, таким образом будет отображена круговая диаграмма для основного отчета и по одной диаграмме-гистограмме для каждой из дочерних таблиц.
Пример отчета, построенного для приведенных метаданных:


Элемент <metadata>
Элемент <metadata>, содержащий метаданные отчета, имеет ряд атрибутов, важных для этого типа страниц:
type="report" - сообщает ispmanager, что данные элемента должны интерпретироваться как описание отчета
name - обязательный атрибут, как и в случае других типов страниц, указывает на func (функцию) в ispmanager, обрабатывающую данный отчет. При отправке данных формы внутри отчета эти данные будут переданы обработчику, связанному с указанным func.
firstrun - при firstrun="no" отчет не будет формироваться при открытии страницы, то есть страница не будет содержать таблиц и диаграмм отчета до тех пор, пока не будут отправлены данные формы с параметрами отчета. Может быть полезным, когда отчет формируется долго.
Строки локализации
С помощью сообщений в разделе messages можно задать описания ко всему отчету и к отдельным таблицам и графикам.
Описание отчета
Можно добавить текстовое описание отчета, которое будет отображаться под заголовком и над формой. Для этого в список сообщений messages в xml отчета необходимо добавить сообщение с именем report_info, например:
<msg name="report_info">Подробный отчет об использовании ресурсов сервера</msg>
Описание к таблице
Чтобы добавить описание к отдельной таблице с данными, в раздел messages XML отчета нужно добавить сообщение с именем в формате table_[BANDNAME], например:
<msg name="table_used_disk”>Использование дискового пространства</msg>
Описание к графику
Чтобы добавить описание к отдельному графику, в раздел messages XML отчета нужно добавить сообщение с именем в формате diagram_[DIAGRAMNAME], например:
<msg name="diagram_used_disk_chart”>График изменения использованного дискового пространства</msg>
Элемент <form>
В этом элементе описывается форма, если ее необходимо отображать. Форма отображается вверху страницы сразу после заголовка и может использоваться для выбора пользователем параметров для построения отчета. Структура этого элемента такая же, как в описании обычных форм.
Обязательно используйте валидаторы для проверки вводимых значений. Так, валидатор check="date" в сочетании с маской mask="9999-99-99" проверяет вводимые значения на соответствие формату “дата YYYY-MM-DD”, валидатор check="int" проверяет, что было введено целое число.
Элемент <band>
Элемент <band> содержит информацию о структуре данных отчета и формате их вывода на странице. Он имеет следующую структуру:
<band>
<query/>
<action/>
<diagram>
[[<line/>]]
</diagram>
<col/>
[[<band>]]
</band>Элементы <band> могут быть вложенными в <band> более высокого уровня. Данные для отображения в <band> задаются либо посредством элементов <query> или <action>, либо передачей данных в элементе <reportdata> (см. ниже в соответствующем разделе). Элементы <query> и <action> не могут находиться вместе в одном и том же <band>.
Атрибуты элемента <band>:
name - имя band, ключевой атрибут
hidden - при hidden="yes" таблица с данными будет скрыта.
Элемент <col>
Представляет столбец данных в таблице отчета.
Атрибуты:
name - имя столбцa, по которому он заполняется данными, ключевой атрибут.
convert - алгоритм кодирования значений в ячейках при подсчете итогов (см. атрибут total). Единственное возможное значение: "bytes" - формат размера данных, например "128 MB".
link - при link="yes" в столбце будет ссылка (якорь) на дочерние элементы данных, а значения из столбца будут заголовками дочерних таблиц.
sort - задаёт тип сортировки данных в столбце. Возможные значения: alpha (алфавитная сортировка; по умолчанию), digit (сортировка в порядке числового возрастания).
total - задаёт тип итогов, отображаемых внизу таблицы с данными. Возможные значения: count (количество строк, имеющих данные в этом столбце), sum (сумма значений ячеек в данном столбце (для числовых столбцов)), sumsuffix (cумма значений ячеек в данном столбце с обработкой суффиксов и convert="money"), avg (среднее значений ячеек в данном столбце).
nestedreport - добавляет ссылку в столбце на другой отчет (функцию), который будет указан в значение атрибута. Также странице другого отчета будут переданы параметры elid — значение в ячейке (или атрибут id из elem), colname — имя столбца, и все параметры формы отчета.
Элемент <query>
Содержит sql-запрос, по которому предоставляются данные для отображения в отчете.
Элемент <query> может быть использован только в XML-описании плагина (см. примеры в конце данной статьи), но не в XML-данных, возвращаемых обработчиком.
В двойных квадратных скобках: [[значение]] - можно передавать в запрос значения из формы или в запрос для дочерней таблицы - значение из основной таблицы (как правило, id записи).
В запросе необходимо использовать псевдонимы для столбцов, чтобы привязать их к элементу <col>.
Пример использования псевдонимов и значений в двойных квадратных скобках см. ниже:
.....
<form>
<!-- получаем от пользователя значение ip-адреса, по которому нужно вывести отчет -->
<field name="ip">
<input name="ip" type="text"/>
</field>
</form>
<band name="emaildomain">
<!-- запрос к БД ispmanager с использованием введенного значения ip-адреса, используются псевдонимы -->
<query>SELECT emaildomain.id AS id, emaildomain.name AS name, emaildomain.ip AS ip as email_cnt FROM emaildomain WHERE ip=[[ip]]</query>
<!-- в атрибут name элемента <col> передается псевдоним из запроса выше -->
<col name="name" type="data" link="yes"/>
<col name="ip" type="data"/>
<band name="email" psort="used">
<!-- запрос для дочерних таблиц с использованием id домена, для которого строится таблица -->
<query>SELECT name AS emailname, used FROM email WHERE domain=[[emaildomain.id]]</query>
<col name="emailname" type="data"/>
<col name="used" type="data"/>
</band>
</band>
.....При использовании отчетов с заданными запросами к БД, необходимо указать источник данных для этих запросов. Чтобы установить источник данных в программе, воспользуйтесь функцией isp_api::SetReportSource(). По умолчанию, все запросы обращаются к текущей базе данных панели без дополнительных уточнений.
Элемент <action>
Содержит запрос к какой-либо функции в программе. Данная функция должна возвращать список, который будет использован как данные для отчета.
Элемент <action> может быть использован только в XML-описании плагина (см. примеры в конце данной статьи), но не в XML-данных, возвращаемых обработчиком.
Значения атрибута name на элементах <col> должны соответствовать именам полей в строках списка.
Кроме имени функции в строке внутри элемента <action> можно передать параметры вызова функции, как продемонстрировано в примере ниже:
.....
<band name="testdata">
<!-- запрашиваем данные об активных сайтах -->
<action>
webdomain?filter=on&active=on
</action>
<!-- используем в таблице отчета имя и папку сайта -->
<col name="name"/>
<col name="docroot"/>
</band>
.....Элемент <diagram>
Содержит описание диаграммы к таблице, заданной родительским элементом <band>
Атрибуты:
name - имя диаграммы.
label - говорит, из какого столбца таблицы брать подписи к диаграмме.
type - задает тип диаграммы. Возможные значения: "pie" (круговая), "histogram" (вертикальные столбцы), "line" (линии).
Типы диаграмм
pie - круговая диаграмма

histogram - диаграмма с вертикальными столбцами


line - диаграмма с одной или несколькими линиями, соединяющими точки значений


Элемент <line>
Содержит информацию о том, откуда брать данные для диаграммы, используется только внутри элементов <diagram> с type="histogram" и type="line". У диаграммы может быть несколько элементов line.
Атрибуты:
data - говорит, из какого столбца брать данные для построения диаграммы
XML данных отчета: элемент <reportdata>
Кроме метаданных, описывающих структуру отчета (элемент <band> внутри <metadata>), для построения отчета требуются данные для отображения в нем, которые передаются в элементе <reportdata>. Этот элемент используется только в случае, когда данные отчета формируются обработчиком. Его не нужно использовать, если данные для отчета формируются с помощью элементов <query> или <action> в метаданных отчета.
<reportdata> является непосредственным родителем для элементов, имена которых соответствуют значению атрибута name элементов <band> верхнего уровня. Таким образом, если в <metadata> есть элемент <band name="traffic">, то внутри <reportdata> будет элемент <traffic>.
Каждая строка таблицы данных описывается элементом <elem>, внутри которого имена элементов соответствуют значениям атрибута name на элементах <col>. Кроме того, в элементах <elem> могут содержаться элементы, описывающие данные для дочерней таблицы, их имена будут соответствовать значениям атрибута name на дочерних элементах <band>.
Проиллюстрируем сказанное выше примером XML, содержащим и метаданные, и данные для построения отчета:
<metadata name="journal.stat" type="report" level="30" firstrun="no" mgr="core">
<!-- <band> верхнего уровня, значение атрибута name соответствует элементу <function> внутри <reportdata> -->
<band name="function">
<diagram name="func" label="funcname" data="percentage" type="pie"/>
<!-- столбец верхнего уровня, значение атрибута name соответствует элементу <funcname> внутри <elem> верхнего уровня -->
<col name="funcname" type="data" total="count" link="yes"/>
<col name="percentage" type="data" sort="digit" sorted="desc" total="sum"/>
<!-- <band> второго уровня, значение атрибута name соответствует элементу <user> внутри <elem> верхнего уровня -->
<band name="user">
<diagram name="user" label="username" type="histogram">
<line data="percentage"/>
</diagram>
<!-- столбец второго уровня, значение атрибута name соответствует элементу <username> внутри <elem> второго уровня -->
<col name="username" type="data" total="count"/>
<col name="percentage" type="data" sort="digit" sorted="desc" total="sum"/>
</band>
</band>
</metadata>
<reportdata>
<!-- данные для таблицы верхнего уровня, описываемой <band name="function"> -->
<function>
<elem>
<!-- значение ячейки в столбце <col name="funcname"> в таблице верхнего уровня -->
<funcname>mgr.edit</funcname>
<percentage>100.00</percentage>
<!-- данные для дочерней таблицы, описываемой <band name="user"> -->
<user>
<elem>
<!-- значение ячейки в столбце <col name="username"> в дочерней таблице -->
<username>root</username>
<percentage>100.00</percentage>
</elem>
</user>
</elem>
</function>
</reportdata>Пример добавления метаданных в XML-описание плагина и использования <query> и <action>
Два приведенных ниже примера выполняют одну и ту же задачу: отобразить информацию о почтовых доменах. Первый пример делает это с помощью элемента <action>, второй - с помощью элемента <query>. Оба варианта предполагают, что XML-метаданные отчета добавляются в XML плагина без использования обработчика. Поскольку обработчик не используется, элемент <handler> в XML-описании плагина в этом случае не нужен. Подробнее о работе с XML-описаниями плагинов читайте в статье “Структура и возможности плагинов”.
Пример с использованием элемента <action>, который позволяет использовать для отчета данные какого-либо существующего списка, в нашем случае - со страницы "Почтовые домены" (func=emaildomains):
<?xml version="1.0" encoding="UTF-8"?>
<mgrdata>
<!-- добавляем в главное меню новую группу и новый пункт -->
<mainmenu level="admin+">
<modernmenu>
<node name="reports">
<node name="emaildomain_report" />
</node>
</modernmenu>
</mainmenu>
<!-- метаданные отчета -->
<metadata name="emaildomain_report" type="report" level="admin+">
<band name="emaildomain" psort="name">
<action>emaildomain?filter=on&active=on</action>
<col name="name" type="data"/>
<col name="owner" type="data"/>
</band>
</metadata>
<lang name="ru">
<!-- сообщения локализации для главного меню -->
<messages name="desktop">
<!-- название группы в modern_menu-->
<msg name="modernmenu_reports">Отчеты</msg>
<!-- название пункта меню -->
<msg name="modernmenu_emaildomain_report">Почтовые домены</msg>
</messages>
<!-- сообщения локализации для страницы отчета -->
<messages name="emaildomain_report">
<msg name="msg_hidedata">Скрыть данные</msg>
<msg name="msg_nodata">Нет данных</msg>
<msg name="msg_showdata">Показать данные</msg>
<msg name="name">Домен</msg>
<msg name="owner">Владелец</msg>
<msg name="email_cnt">Количество почтовых ящиков</msg>
<msg name="report_info">Статистика почтовых доменов</msg>
<msg name="title">Отчёт: Почтовые домены</msg>
</messages>
</lang>
</mgrdata>Пример с использованием элемента <query>, формой, диаграммой и вложенными таблицами:
<?xml version="1.0" encoding="UTF-8"?>
<mgrdata>
<!-- добавляем в главное меню новую группу и новый пункт -->
<mainmenu level="admin+">
<modernmenu>
<node name="reports">
<node name="emaildomain_report" />
</node>
</modernmenu>
</mainmenu>
<!-- метаданные отчета -->
<metadata name="emaildomain_report" type="report" level="admin+" firstrun="no">
<form>
<field name="ip">
<input name="ip" type="text"/>
</field>
</form>
<band name="emaildomain" psort="name">
<query>SELECT emaildomain.id AS id, emaildomain.name AS name, emaildomain.ip AS ip, COUNT(email.id) as email_cnt FROM emaildomain, email WHERE email.domain=emaildomain.id AND ip=[[ip]] GROUP BY emaildomain.id</query>
<col name="name" type="data" link="yes"/>
<col name="email_cnt" type="data"/>
<diagram type="pie" name="emaildomain" data="email_cnt" label="name" />
<band name="email" psort="used">
<query>SELECT name AS emailname, used FROM email WHERE domain=[[emaildomain.id]]</query>
<col name="emailname" type="data"/>
<col name="used" type="data"/>
</band>
</band>
</metadata>
<lang name="ru">
<!-- сообщения локализации для главного меню -->
<messages name="desktop">
<!-- название группы в modern_menu-->
<msg name="modernmenu_reports">Отчеты</msg>
<!-- сообщения для modern_menu, название пункта -->
<msg name="modernmenu_emaildomain_report">Почтовые домены</msg>
</messages>
<!-- сообщения локализации для страницы отчета -->
<messages name="emaildomain_report">
<msg name="msg_hidedata">Скрыть данные</msg>
<msg name="msg_nodata">Нет данных</msg>
<msg name="msg_showdata">Показать данные</msg>
<msg name="name">Домен</msg>
<msg name="ip">IP</msg>
<msg name="email_cnt">Количество почтовых ящиков</msg>
<msg name="emailname">Имя ящика</msg>
<msg name="used">Использовано места на диске</msg>
<msg name="report_info">Статистика почтовых доменов</msg>
<msg name="title">Отчёт: Почтовые домены</msg>
</messages>
</lang>
</mgrdata>Отчет, созданный кодом из второго примера:

