Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
abills:docs:development:manual:ru [2018/01/14 15:59]
anton [Работа с БД]
abills:docs:development:manual:ru [2019/02/21 10:57] (текущий)
andriy [Основная часть модуля - вебинтерфейс]
Строка 7: Строка 7:
   * Работа с БД (''​dbcore.pm''​)   * Работа с БД (''​dbcore.pm''​)
   * Работа с визуализацией   * Работа с визуализацией
 +  * Базовые библиотеки
   * Файл конфигурации   * Файл конфигурации
  
Строка 16: Строка 17:
   * Класса менеджера сущностей в БД. (''​Abills/​mysql/​Example.pm''​)   * Класса менеджера сущностей в БД. (''​Abills/​mysql/​Example.pm''​)
   * Файл с логикой (функциями) ''​Abills/​modules/​Example/​webinterface''​   * Файл с логикой (функциями) ''​Abills/​modules/​Example/​webinterface''​
-  * Описания меню ''​Abills/​modules/​Example/​config''​+  * Описание меню ''​Abills/​modules/​Example/​config''​
   * Дополнительные файлы словарных переменных (необязательно) (''​Abills/​modules/​lng_english.pl''​)   * Дополнительные файлы словарных переменных (необязательно) (''​Abills/​modules/​lng_english.pl''​)
   * Файла описания схемы БД (''​db/​Example.sql''​)   * Файла описания схемы БД (''​db/​Example.sql''​)
  
 Теперь,​ когда мы рассмотрели какие части должны быть в самом модуле,​ детально рассмотрим взаимодействие модуля с частями фреймворка.\\ Теперь,​ когда мы рассмотрели какие части должны быть в самом модуле,​ детально рассмотрим взаимодействие модуля с частями фреймворка.\\
 +
 +==== Регистрация модуля в движке ===
 +После добавления имени модуля в массив ''​@MODULES''​ (**libexec/​config.pl**),​ при инициализации движка читается файл ''​config''​ из папки модуля и словарь с переменными текущего языка пользователя вебинтерфейса. Функции из ''​config''​ добавляются в глобальные реестр функций интерфейса,​ при этом каждой присваивается особый числовой индекс,​ который позволяет вызвать эту функцию.\\
 +
 +Сами функции должны быть доступны в ''​webinterface''​ (или быть импортированы из других пакетов внутри ''​webinterface''​)\\
 +Поскольку все ''​webinterface''​ выполняются в глобальной области видимости,​ к имени каждой функции нужно добавлять имя модуля.\\
 +
 +==== Основная часть модуля - вебинтерфейс ====
 +В основном случае,​ логика вебинтерфейса проста и прозрачна - получить данные,​ обработать и вывести в каком-то виде (шаблон или таблица).\\
 +Фреймворк неявно (через глобальную область видимости) передаёт в ''​webinterface''​ следующие переменные:​
 +^ Имя ^ Описание ^
 +|%LANG ​ |хеш-масив словаря |
 +|%FORM ​ |хеш-масив значений переданных на страницу (GET или POST запросом) |
 +|$html ​ |Обьект визуализации (экземпляр класса ''​Abills::​HTML''​) |
 +|$users |Менеджер работы с пользователями (экземпляр класса ''​Users''​). **Использовать только в функциях админ. интерфейса.** |
 +|$db    |Соединение с БД |
 +|$admin |Менеджер работы с администраторами (экземпляр класса ''​Admins''​)|
 +|%conf ​ |хеш-масив конфигурационного файла |
 +
 +Для примера рассмотрим работу с сущностью ''​entity''​ в модуле ''​Example''​\\
 +
 +Получить данные можно несколькими способами:​
 +  * Из БД (ссылка на работу с БД)
 +  * Из внешнего источника (здесь ссылка на web_request)
 +  * Из файловой системы
 +  * Из других модулей
 +
 +Для CRUD операций в ABillS принято использовать одну отдельную функцию в которой происходят следующие операции:​
 +  * Добавление новой сущности
 +  * Редактирование сущности
 +  * Удаление сущности
 +  * Отображение списка сущностей
 +  * Отображение сущности (совмещено с редактированием)
 +
 +Если используется работа с БД, то внутри файла ''​webinterface''​ инициализируется обьект менеджера работы с сущностями.
 +<code perl>
 +use Example; # Загрузить файл /​usr/​abills/​Abills/​mysql/​Example.pm
 +my $Example = Example->​new($db,​ $admin, \%conf); # Создать объект менеджера
 +</​code>​
 +
 +В коде функция работы с сущностями будет выглядеть так:
 +<code perl>
 +#​**********************************************************
 +=head2 entity_example_main()
 +
 +=cut
 +#​**********************************************************
 +sub entity_example_main{
 +  # Хеш для переменных шаблона обьявляется в области видимости функции
 +  my %template_args = ();
 +  ​
 +  # Флаг отображения шаблона
 +  my $show_template = $FORM{add_form} || 0;
 +  ​
 +  # Здесь используется глобальный хеш %FORM, ​
 +  # который доступен в глобальной области видимости
 +  # и включает значения,​ полученные из GET или POST запроса.
 +  if ($FORM{add}) {
 +    $Example->​entity_add({%FORM});​
 +    $show_template = !show_result($Example,​ $lang{ADDED});​
 +  }
 +  elsif ($FORM{change}) {
 +    $Example->​entity_change({%FORM});​
 +    show_result($Example,​ $lang{CHANGED});​
 +    $show_template = 1;
 +  }
 +  elsif ($FORM{chg}) {
 +    my $entity_info = $Example->​entity_info($FORM{chg});​
 +    if (!_error_show($Entity)) {
 +      %template_args = %{$entity_info};​
 +      $show_template = 1;
 +    }
 +  }
 +  elsif ($FORM{del} && $FORM{COMMENTS}) {
 +    $Example->​entity_del({ ID => $FORM{del}, COMMENTS => $FORM{COMMENTS} });
 +    show_result($Example,​ $lang{DELETED});​
 +  }
 +  ​
 +  # Использование этой точки выхода
 +  # позволяет использовать эту же функцию
 +  # только для выполнения операции (например AJAX запросом)
 +  return 1 if $FORM{MESSAGE_ONLY};​
 +
 +  # Здесь собрана логика обработки данных для отображения шаблона  ​
 +  if ($show_template) {
 +    # Отображение шаблона
 +    $html->​tpl_show(
 +      _include('​example_entity',​ '​Example'​),​
 +      {
 +        %TEMPLATE_ARGS,​
 +        %FORM,
 +        SUBMIT_BTN_ACTION => ($FORM{chg}) ? '​change'​ : '​add',​
 +        SUBMIT_BTN_NAME ​  => ($FORM{chg}) ? $lang{CHANGE} : $lang{ADD},
 +      }
 +    );
 +  }
 +  ​
 +  # Использование этой точки выхода
 +  # позволяет использовать эту же функцию
 +  # для отображения шаблона изменения внутри модального окна
 +  return 1 if ($FORM{TEMPLATE_ONLY});​
 +  ​
 +  # Использование библиотеки Abills::​ResultFormer
 +  # для получения списка из БД (метод $Example->​entities_list($attr)) и построения таблицы (Abills::​HTML->​table($attr))
 +  my Abills::​HTML $table; ($table) = result_former(
 +    {
 +      INPUT_DATA ​     => $Example,
 +      FUNCTION ​       => '​entities_list',​
 +      BASE_FIELDS ​    => 0,
 +      DEFAULT_FIELDS ​ => '​ID,​NAME,​VALUE',​
 +      FUNCTION_FIELDS => '​change,​del',​
 +      SKIP_USER_TITLE => 1,
 +      EXT_FIELDS ​     => 0,
 +      EXT_TITLES ​     => {
 +        id             => '#',​
 +        name           => $lang{NAME},​
 +        value          => $lang{VALUE},​
 +      },
 +      TABLE => {
 +        width   => '​100%',​
 +        caption => $lang{ENTITY},​
 +        ID      => '​ENTITIES_TABLE',​
 +        EXPORT ​ => 1,
 +        MENU    => "​$lang{ADD}:​index=$index&​add_form=1:​add"​
 +      },
 +      MAKE_ROWS ​    => 1,
 +      SEARCH_FORMER => 1,
 +      MODULE ​       => '​Example',​
 +    }
 +  );
 +  ​
 +  # Таблицу нужно выводить отдельно
 +  print $table->​show();​
 +  ​
 +  # Сообщаем движку,​ что функция завершилась нормально
 +  return 1;
 +}
 +</​code>​
  
  
  
 ==== Работа с БД ==== ==== Работа с БД ====
-Все классы работы с БД наследуются от ''​dbcore''​. В таком случае в классе становятся доступны следующие методы:​\\+Все классы работы с БД наследуются от ''​dbcore''​. ​\\ 
 +В таком случае в классе становятся доступны следующие методы:​\\
 | query($query,​ $type, $attr) | выполнение запроса к БД ( В основном используется для операции ''​SELECT''​ )| | query($query,​ $type, $attr) | выполнение запроса к БД ( В основном используется для операции ''​SELECT''​ )|
 | changes($table,​ $data, $attr) | обёртка над query("​UPDATE ..."). Сравнивает данные в таблице и изменяет только поля с обновлёнными значениями. Может добавлять в системный лог записи об изменении| | changes($table,​ $data, $attr) | обёртка над query("​UPDATE ..."). Сравнивает данные в таблице и изменяет только поля с обновлёнными значениями. Может добавлять в системный лог записи об изменении|
Строка 34: Строка 174:
 Все эти методы должны вызываться в объекте с заданными полями ''​conf'',​ ''​db'',​ ''​admin''​ (''​$self->​{db}'',​ ''​$self->​{conf}'',​ ''​$self->​{admin}''​). \\ Все эти методы должны вызываться в объекте с заданными полями ''​conf'',​ ''​db'',​ ''​admin''​ (''​$self->​{db}'',​ ''​$self->​{conf}'',​ ''​$self->​{admin}''​). \\
  
-Рассмотрим работу с каждым из методов детальнее.+Конструктор в общем случае должен реализовать как минимум этот функционал 
 +<code perl> 
 +#​********************************************************** 
 +=head2 new($db, $admin, \%conf) - Constructor for Example 
 + 
 +=cut 
 +#​********************************************************** 
 +sub new{ 
 +  my ($class, $db, $admin, $CONF) = @_; 
 +  my $self = { 
 +    db    => $db, 
 +    admin => $admin, 
 +    conf  => $CONF 
 +  }; 
 + 
 +  bless($self,​ $class); 
 +  return $self; 
 +
 +</​code>​ 
 + 
 +Рассмотрим работу с каждым из унаследованных ​методов детальнее.
 <​accordion><​panel title="​**Таблица,​ которая используется в запросах**"><​code mysql> <​accordion><​panel title="​**Таблица,​ которая используется в запросах**"><​code mysql>
  
-CREATE TABLE `example` (+CREATE TABLE `example_entity` (
   `id` INT UNSIGNED PRIMARY AUTO_INCREMENT,​   `id` INT UNSIGNED PRIMARY AUTO_INCREMENT,​
   `name` VARCHAR(40) NOT NULL,   `name` VARCHAR(40) NOT NULL,
Строка 56: Строка 216:
 Рассмотрим примеры запросов и результат выполнения. Рассмотрим примеры запросов и результат выполнения.
 <code perl> <code perl>
-  $self->​query("​SELECT * FROM example");+  $self->​query("​SELECT * FROM example_entity");
 </​code>​ </​code>​
-Результатом выполнения будет запись в ''​$self->​{list}''​ двумерного масива содержимого таблицы ''​example''​.+Результатом выполнения будет запись в ''​$self->​{list}''​ двумерного масива содержимого таблицы ''​example_entity''​.
  
 <code perl> <code perl>
-  $self->​query("​SELECT * FROM example", undef, { COLS_NAME => 1 })+  $self->​query("​SELECT * FROM example_entity", undef, { COLS_NAME => 1 })
 </​code>​ </​code>​
 Здесь в качестве $type мы указываем ''​undef''​ для получения данных из базы. ''​$attr->​{COLS_NAME} => 1''​ говорит,​ что мы хотим получить результаты в виде масива хешей. Результатом выполнения будет запись в $self->​{list} масива хешей, где ключами хеша будут названия столбцов таблицы,​ а значениями - соответственно значения.\\ Здесь в качестве $type мы указываем ''​undef''​ для получения данных из базы. ''​$attr->​{COLS_NAME} => 1''​ говорит,​ что мы хотим получить результаты в виде масива хешей. Результатом выполнения будет запись в $self->​{list} масива хешей, где ключами хеша будут названия столбцов таблицы,​ а значениями - соответственно значения.\\
Строка 68: Строка 228:
 Следующий пример удобен,​ когда в коде нам нужно будет сформировать простой список выбора или поисковую таблицу ключ - значение. (Например,​ по id строки) Следующий пример удобен,​ когда в коде нам нужно будет сформировать простой список выбора или поисковую таблицу ключ - значение. (Например,​ по id строки)
 <code perl> <code perl>
-  $self->​query("​SELECT id,name FROM example", undef, { LIST2HASH => '​id,​name'​ });+  $self->​query("​SELECT id,name FROM example_entity", undef, { LIST2HASH => '​id,​name'​ });
 </​code>​ </​code>​
 Результатом выполнения запроса будет запись в ''​$self->​{list_hash}''​ хеша, где ключ ''​id''​ строки,​ а значение ''​name''​.\\ Результатом выполнения запроса будет запись в ''​$self->​{list_hash}''​ хеша, где ключ ''​id''​ строки,​ а значение ''​name''​.\\
Строка 74: Строка 234:
 Теперь рассмотрим ключ ''​COLS_UPPER''​. Теперь рассмотрим ключ ''​COLS_UPPER''​.
 <code perl> <code perl>
-  $self->​query("​SELECT * FROM example", undef, { COLS_NAME => 1, COLS_UPPER => 1 })+  $self->​query("​SELECT * FROM example_entity", undef, { COLS_NAME => 1, COLS_UPPER => 1 })
 </​code>​ </​code>​
 Использование этого ключа связано с системой шаблонов,​ по утверждённому стандарту,​ названия столбцом таблицы указываются в __lowercase__,​ а переменные шаблона указываются в __UPPERCASE__. Таким образом,​ для передачи данных из БД в шаблон,​ пришлось бы вручную переназначать ​ переменные при передаче в шаблон. Ключ ''​COLS_UPPER''​ дублирует ключи в хеше в в виде UPPERCASE, что позволяет передавать строки результата в шаблон без дополнительной логики. Использование этого ключа связано с системой шаблонов,​ по утверждённому стандарту,​ названия столбцом таблицы указываются в __lowercase__,​ а переменные шаблона указываются в __UPPERCASE__. Таким образом,​ для передачи данных из БД в шаблон,​ пришлось бы вручную переназначать ​ переменные при передаче в шаблон. Ключ ''​COLS_UPPER''​ дублирует ключи в хеше в в виде UPPERCASE, что позволяет передавать строки результата в шаблон без дополнительной логики.
  
 +
 +==== Создание базовой страницы ====
 +
 +Создаем базовую страницу сервиса
 +
 +''​cgi-bin/​hello.cgi''​
 +  ​
 +<​code>​
 +#​!/​usr/​bin/​perl
 +=head1 NAME
 +
 + ​Hello ​ world
 +
 +=cut
 +
 +use strict;
 +use warnings;
 +
 +# Включение нужных путей
 +BEGIN {
 +  our $libpath = '​../';​
 +  my $sql_type = '​mysql';​
 +  unshift(@INC,​
 +    $libpath . "​Abills/​$sql_type/",​
 +    $libpath . "​Abills/​modules/",​
 +    $libpath . '/​lib/',​
 +    $libpath . '/​Abills/',​
 +    $libpath
 +  );
 +}
 +
 +#​Модуль конфигурации
 +use Conf;
 +our (
 +  $libpath,
 +  %conf,
 +  %lang,
 +  $base_dir,
 +);
 +
 +# конфигурационный файл
 +do "​../​libexec/​config.pl";​
 +
 +# HTML визуализация
 +use Abills::​HTML;​
 +my $html = Abills::​HTML->​new(
 +  {
 +    IMG_PATH => '​img/',​
 +    NO_PRINT => 1,
 +    CONF     => \%conf,
 +    CHARSET ​ => $conf{default_charset},​
 +  }
 +);
 +
 +# Подключение базы
 +use Abills::​SQL;​
 +my $db = Abills::​SQL->​connect($conf{dbtype},​ $conf{dbhost},​ $conf{dbname},​ $conf{dbuser},​ $conf{dbpasswd},​ {
 +  CHARSET => ($conf{dbcharset}) ? $conf{dbcharset} : undef
 +});
 +
 +# Включение базовых словарей
 +if($html->​{language} ne '​english'​) {
 +  do $libpath . "/​language/​english.pl";​
 +}
 +
 +if(-f $libpath . "/​language/​$html->​{language}.pl"​) {
 +  do $libpath."/​language/​$html->​{language}.pl";​
 +}
 +
 +# Подключение модуля работы с шаблонами ​
 +require Abills::​Templates;​
 +
 +# Включение конфигурационного файла
 +Conf->​new($db,​ undef, \%conf);
 +
 +$html->​{METATAGS} = templates('​metatags_client'​);​
 +
 +print $html->​header();​
 +
 +# Диалоговое окно приветсвия
 +print $html->​message('​info',​ $lang{INFO},​ "Hello world\nSystem name '​$conf{WEB_TITLE}'"​);​
 +
 +1;
 +</​code>​