Руководство для разработчиков

Описание отчетов

Введение

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

Отчет в разделе "Журнал операций"
Отчет в разделе "Журнал операций"

Дальнейшее изложение предполагает, что читатель знаком с общей структурой метаданных, по которым строится 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 — имя столбца, и все параметры формы отчета.

Содержит 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&amp;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&amp;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>

Отчет, созданный кодом из второго примера: