Использовние MetaXLib для PHP на практике


Автор(ы): Дмитриев Н.А.

Оглавление



Введение.

Библиотека MetaXlib for PHP (далее MXL), разработана с целью упрощения и ускорения разработки, серьезных Web приложений, в которых требуется работать непосредственно с данными, в достаточно большом объеме, через таблицы, списки, комбобоксы.

Структура

MXL базируется на большой библиотеке extJS фирмы Sencha, которая содержит полную коллекцию визуальных виджетов с хорошим функционалом. По моему мнению, более полной и функциональной библиотеки на данный момент не существует. На момент написания данного мануала используется версия 3.4.
Пройдемся по структуре нашей библиотеки.
Структура нашего сайта должна быть следующей:

01

Orgn – в ней располагается наш проект и папки, которые необходимы для работы проекта:
Src – библиотека MetaXLib
MetaXLib_cfg – папка с конфигами библиотеки (ниже опишем подробнее содержимое данной папки, т.к. это не просто конфиг библиотеки, а по сути -  конфигурация виджетов библиотеки по отношении к нашему проекту)
Libs – тут мы видим еще две папки – DB – папка с библиотеками для работы с базой данных (в нашем случае MySQL) и папка extJS – папка где хранится большая JS библиотека, на основе которой и построена наша библиотека.

В корне пара PHP скриптов, которые инициализируют библиотеку
init.php
autoload.php

init.php – содержит скрипт запуска и инициализации библиотеки:


?php
/**
 * Файл конфигурирования библиотеки.
 *  1. Регистрируется автозагрузчик;
 *  2. Указывается путь к файлу конфигрураций проекта (с путями).
**/
    require_once realpath(dirname(__FILE__).'/autoload.php');
    mxl_autoload::register();

    include_once realpath(dirname(__FILE__).'/../MetaXLib_cfg/MetaXLib_cfg.php');
?

autoload.php – скрипт - загрузчик классов по имени, требуется для работы библиотеки. Структуру данного файла пока рассматривать не будем, т.к. на данном этапе, этого не требуется для понимания работы библиотеки.
Последняя строка скрипта указывает на путь к конфигурации библиотеки.

Для начала оговоримся, что у вас есть и настроен рабочий web сервер, например apache, установлен PHP версии не ниже 5.2, также имеется и настроена база данных MySQL, потому как без данного инструментария мы ничего не сделаем. Для простоты решения можно пользоваться достаточно популярным пакетом XAMPP.
В данном шаге мы рассмотрим конфигурирование библиотеки, для начала изучим файлы конфигурации MetaXLib_cfg.php и mxl_cfg.mxl (не забываем, что мы прописали путь к библиотеке инициализации в файле init.php).
Принципиально, в данных файлах менять ничего не требуется, если вы согласны со структурой приложения, предлагаемой нами. Все пути к папкам библиотеки указаны в файле mxl_cfg.mxl, вот кусок, где и указываются пути:


    /**
    * Раздел задания  путей источников данных, и части логики относящейся к 
    * использованию  путей и всего с ними связанного в библиотеке
    */
  "path"  : {
    "separator"       : "\/",
    /**
    * если указан абсолютный путь то загружаем по  нему, 
    * в противном случае относительно каталога  конфигурации библиотеки.
    * В качестве разделителей необходимо  использовать \/.
    */ 
    "core_enums"      : "\/core\/enums", // перечисления 
    "core_logicbases" : "\/core\/logicbases", //описание логических баз 
    
    //три последующие строки – пути к описателям (json файлы) виджетов
    "dict_comboboxes"  : "\/dict\/comboboxes",
    "dict_grids"      : "\/dict\/grids",
    "dict_lists"      : "\/dict\/lists",
    
    //валидаторы виджетов 
    "dict_validators" : "\/dict\/validators",
    //элементы отображения 
    "dict_renderers"  : "\/dict\/renderers",
    //сниппеты вызываемые из валидаторов 
    "snippet_validate":  "\/dict\/validators\/snippet_validate",
    
    "localizations"   : "\/localizations", //файлы локализации
    
    /**
    * Поддиректорий к исполняемым файлам словаря (сниппетам).
    *  Внимание!!! Указывать только имя каталога, без разделителей каталогов!!!
    */
    "snippet"         : "snippet"
}

Повторюсь, для тех, кто не знаком с библиотекой extJS, визуальные элементы, которые строятся посредством данной библиотеки, называют «виджетами», а вообще для того чтобы можно было полноценно использовать библиотеку, знание (хотя бы со «словарем»)  extJS 3 обязательно, иначе вы просто не поймете, что к чему.
Кодирование внешнего вида и реакций виджета делается посредством файлов в формате JSON, расширение которых в наших проектах и примерах - .mxl

Наверное, отвлечемся от теории и позанимаемся самой простой практикой.
Итак, нам потребуется для начала:

  1. Скрипт на PHP, в котором мы вызовем процедуру отрисовки нашего виджета.
  2. html файл, который собственно и будет отображать нашу табличку
  3. Файл конфигурации, в котором мы опишем структуру нашей таблицы
  4. Файл описания логической БД (собственно коннект к базе, из которой мы достаем данные)

Вроде бы все, теперь по порядку, что где содержится.
Попробуем создать простое Web приложение – персональный органайзер, который будет хранить контакты знакомых и не очень людей.
Создадим файл - индекс, из которого будем вызывать наши страницы:
Тут все просто, поэтому это описание пропустим и сразу перейдем к нашей первой простой таблице.

Шаг 1. Настройка соединения с БД

Создадим описание подключения к базе данных MySQL, для этого в папке MetaXLib_cfg/core/logicbases создадим файл orgndb.php со следующим содержимым:

@define('IN_SYS', true);
@define('USE_ENCRYPTED_PASSWORD', false);

$table_prefix = '';
$sys_table_prefix = '';

//тут ясно описан коннект к базе
$dbhost = 'localhost';
$dbport = '3306';
$dbms = 'mysql';
$dbname = 'orgn';
$dbuser = 'root';
$dbpasswd = '1234';
require_once realpath(realpath(dirname(__FILE__)).'\..\..\..\libs\db\\' .$dbms. '.php');
//инициируем подключение и создаем экземпляр соединения к базе.
$sql_db = 'dbal_' . $dbms;

$MXL_DB = new $sql_db();
$MXL_DB->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, false);

unset($dbpasswd);
//добавляем логическую базу.
//наша база будет доступна по имени «orgndb»
$this->addLogicBase('orgndb', 'Персональный органайзер', $MXL_DB);

Шаг 2.  Таблица в базе данных
Далее сделаем в нашей базе таблицу city с двумя полями:
city_id и CITY_NAME.
city_id – ключевое поле с автоинкрементном;
CITY_NAME – текстовое поле (CITY_NAME) с длинной 255 для хранения имен городов.

Шаг 3. Описание таблицы в формате JSON
Таблица строится на основе описания в формате JSON, где описываются поля и их типы, а также внешний вид таблицы. Хранится описание таблиц в папке MetaXLib_cfg/dict/grids. Создадим тут файл refcity.mxl (заметьте, расширение именно mxl) со следующим содержимым:


  {
"name"          : "refcity",
"caption"       : "Справочник: Города",

"logicBaseName" : "orgndb",
"tableName"     : "city",
"primaryKey"    : "CITY_ID",

"queryText"     : "",
"where"         : "",
"order"         : "",

"options" : {
  "readOnly"         : false, "validator"     : "",
  "selectByLeftJoin" : false,

  "manyRowsSaveMode" : true,
  "paginMode"        : false, "pageStart" : 0, "pageSize" : 0,

  "nextColOnEnter"   : true,
  "clicksToEdit"     : 1,

  "height"           : 300,
  "width"            : 300
},

"fields" : [
  {"n":"CITY_ID",      "c":"Код города",
    "w":"10", "dt":"int",    "dl":"0",
    "a":"|HD|",   "mr":""},
  {"n":"CITY_NAME",	 "c":"Город",
    "w":"30", "dt":"string", "dl":"250",
    "a":"",       "mr":""}
]
}

  

Пока разберем только поля, остальные опции будут рассказаны дальше, поля хранятся в массиве fields, строки которого заключены в фигурные скобки, с разделителем - запятой:
n – имя поля, совпадает с именем поля в БД
с – заголовок колонки
w – ширина колонки в символах
dt – сокращенно от data type, тип данных
dl – длинна данных
a – атрибут, |HD| - скрытое поле (подробно об атрибутах в приложении)
mr - маска редактирования.
Как видите, первую колонку мы сделали скрытой, да и, собственно, зачем отображать первичный ключ/код таблицы, пользователю он ни к чему.

Шаг 4. Вывод таблицы
Теперь можно приступать к выводу нашей подготовленной таблицы.

В файле index.php создадим ссылку на файл ref_city.php, который собственно и будет выводить нашу таблицу. Привожу содержимое файла ref_city.php:


    <?php
//подключаем библиотеку MXL
include_once realpath(dirname(__FILE__).'\src\init.php');

//создаем экземпляр класса виджеты
$WGS = new mxl_widget_widgets();

//добавляем в виджеты новый виджет грид (‘имя виджета’, ‘имя модели грида’)
// имя модели грида – refcity мы описывали выше в файле refcity.mxl
$WGS->addWidget(new mxl_widget_dbgrid('refcity1', 'refcity'));

//создаем файл вывода JS скрипта с построителем грида
$fileName = realpath(dirname(__FILE__).'\js_cash').'\ref_city.js';
$WGS->WriteJScript($fileName);
// далее выводим все.
?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Справочник Города</title>
<link rel="stylesheet" type="text/css" href="./libs/extjs/resources/css/ext-all.css">
<link rel="stylesheet" href="./libs/extjs/plugins/Ext.ux.grid.GridSummary.css"/>

<script type="text/javascript" src="./libs/extjs/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="./libs/extjs/ext-all.js"></script>
<script type="text/javascript" src="./libs/extjs/plugins/Ext.ux.grid.GridSummary.js"></script>
<script type="text/javascript" src="./libs/extjs/plugins/ux/CheckColumn.js"></script>

<script type="text/javascript" src="./src/js/metaxlib.js"></script>

<script type="text/javascript" src="./js_cash/ref_city.js"></script>

<script type="text/javascript">
	Ext.BLANK_IMAGE_URL = './libs/extjs/resources/images/default/s.gif';
	Ext.isSecure = true;
	//после загрузки страницы начинаем генерацию виджетов
	Ext.onReady(function(){
      startAutoGenScript();
	});
</script>
</head>
<body>
<?php include '/inc/top_head.php'; ?>
<br><br>
<!-- в приведенный ниже div и будет выводиться наша таблица,
     ID формируется по правилам dbg_имяГрида  -->
	<div id="dbg_refcity1" style="padding-left:50px"></div>
</body>
</html>
    

Получаем следующий результат

2

Как видим, у нас на выходе совершенно обычная extJS таблица, которая автоматически будет подтягивать данные из БД и сохранять изменения.

Далее по такому же принципу создадим справочники улиц и групп контактов:

MySQL – streets (street_id, STREET_NAME),  cont_groups (group_id, group_name).

MetaXLib_cfg/dict/grids

3

Создание первого приложения

Теперь перейдем к достаточно обширной части нашей инструкции, выводу справочнику людей и связи их с группами контактов.

Важное примечание, дата в базе данных должна храниться в виде целого числа, т.е. в формате (INT длинной 11), т.к. манипуляции над датами идут в UNIX формате, т.е. целого числа. Учитывайте это при проектировании базы данных.

Спроектируем таблицу БД и саму таблицу, которая будет выводить нам контакты с возможностью редактирования.
Наша БД

4

Таблица peoples в БД

5

В данной таблице city и street – id ключей таблиц city и streets.
Теперь сделаем mlx файл, который будет описывать нашу extJS таблицу.
Файл назовем refpeoples.mxl


  {
"name"          : "refpeoples",
"caption"       : "Справочник: Люди",

"logicBaseName" : "orgndb",
"tableName"     : "peoples",
"primaryKey"    : "people_id",
"queryText"     : "",
"where"         : "",
"order"         : "",

"options" : {
	"readOnly"         : false, "validator"     : "",
	"selectByLeftJoin" : false,

	"manyRowsSaveMode" : true,
	"paginMode"        : true, "pageStart" : 0, "pageSize" : 50,

	"nextColOnEnter"   : true,
	"clicksToEdit"     : 2,

	"height"           : 300,
	"width"            : 800
},

"fields" : [
 {"n":"people_id",	"c":"Код", "w":10,  "dt":"int",
   "dl":0,  "a":"|HD|", "mr":""},
 {"n":"fio", "c":"Ф.И.О.",  "w":35,	"dt":"string",
   "dl":250,  "a":"", "mr":""},
 {"n":"birthday", "c":"Дата<br>рождения",	"w":12,
   "dt":"date", "dl":0, "a":"", "mr":"", "formatD":"d.m.Y"},
	{"n":"city", "c":"Город", "w":25,  "dt":"string",
   "dl":8,  "a":"|ENUM|", "mr":""},
	{"n":"street", "c":"Улица", "w":25,  "dt":"string",
   "dl":8, "a":"|ENUM|", "mr":""},
	{"n":"home", "c":"Дом", "w":8,  "dt":"int",
   "dl":11,  "a":"", "mr":""},
 {"n":"corp", "c":"Корп.",  "w":7, "dt":"string",
   "dl":11, "a":"", "mr":""},
	{"n":"flat", "c":"Кв.", "w":7,	"dt":"int",
   "dl":11, "a":"", "mr":""}
],

"relations" : [
	{"fn":"city",  "rl":"", "cn":"cbx_city_dbsql", "lw":300},
	{"fn":"street",  "rl":"", "cn":"cbx_street_dbsql", "lw":300}
],

"totals" : {
  	"grid" : [
  		{"fn":"people_id",   "tp":"count", "c":"people_id Count: "}  		
  	],
  	"footer" : [

  		{"fn":"flat", "tp":"sum", "c":"", "h":"flat ids summary value"}
  		
  	]
  }
}

  

Структура mxl файла таблицы

Пора разобрать структуру mxl файла для грида.


name          : имя грида,
caption       : заголовок грида,
logicBaseName : имя логической бд,
tableName     : имя базовой таблицы,
primaryKey    : имя ключевого поля в базовой таблице,
queryText     : запрос с макросами для получения данных,
                если не указано запрос формируется автоматом вида select {поля} from {таблица}
where         : ограничение на отбор данных, так же можно оставить пустым
order         : порядок сортировки,


"options" : {
	"readOnly"         : false/true - возможно ли редактировать данные,
"validator"        : "имя файла валидации, расположенного в папке валидации",
"renderer"         : "имя файла скрипта рендерера, расположенного в папке рендереров",
	"nextColOnEnter"   : false/true - режим перехода к редактированию следующего поля строки по enter,
	"selectByLeftJoin" : false/true - Строить запрос с использованием конструкций left join,
	"manyRowsSaveMode" : false/true - режим сохранения множества строк,
	
 "paginMode"        : false/true - режим постраничной работы грида, 
 "pageStart"        : 0 - задание начальной страницы активно при постраничном режиме работы, 
 "pageSize"         : 12 - задание кол-ва строк на странице,

	"clicksToEdit"     : 1 - число кликов мышки для перехода в режим редактирования,
	"height"           : 405 - высота грида в пикселях,
	"width"            : 800 - ширина грида в пикселях
},

раздел описания полей
"fields" : [
	{"n":"имя поля 1", "c":"Заголовок 1", "w":10 - ширина, "dt":"тип данных",
		 "dl":размер данных, "a":"атрибуты", "mr":"маска редактирования"},

	{"n":"имя поля N", "c":"Заголовок N", "w":25 - ширина, "dt":"тип данных",
		 "dl":размер данных, "a":"атрибуты", "mr":"маска редактирования"},
],

раздел описания связей полей
"relations" : [
пример описания для enum
{"fn":"имя поля", "rl":"", "cn":"имя комбобокса"},
пример описания для связи с другой таблицой по ключу
	{"fn":"имя поля", "rl":"таблица; алиас; поле из которого будет браться значение;
        алиас базовой таблицы.
        ключевое поле в базовой таблице=алиас. ключевое поле в таблице связи",
	 "cn":"@имя комбобокса для выбора данных"},
	{"fn":"имя поля", "rl":"алиас таблицы связи;
					 поле из которого будет заполнятся в таблице связи",  "cn":""},
],
раздел задания значений по умолчанию, для полей со связями к другим 
таблицам можно указывать только значение ключевого поля, остальные 
значения полей подтянуться автоматически
"defaults" : [
	{"fn":"имя поля 1", "df":"значение по умолчанию 1"},

	{"fn":"имя поля N", "df":"значение по умолчанию N"}
],

раздел задания итогов
"totals" : {

итоги по гриду
	"grid" : [
		{"fn":"имя поля для итога", "tp":"тип итога", "c":"заголовок итога"},
		...
		{"fn":"имя поля для итога", "tp":"тип итога", "c":"заголовок итога"}
	],

	итоги в футере
	"footer" : [
		заголовок может принимать сложные значения
		для определения как отображать итог:
		Значения макроса разделяются '|';
		Макрос для вставки значения #VTINS;
		Возможны три ситуации указания значений:
			1. идентификатор значения не заполнен - общий заголовок
			2. идентификатор #NVAL= - значение определяющие текст отображения для 
				ситуации, когда итог не имеет значение.
			3. "значение=" - для указанного значения будет выведен этот текст
		{"fn":"имя поля для итога", "tp":"тип итога",
			 "c":"заголовок итога", "h": "текст всплывающего окошка"},
		... 
		{"fn":"имя поля для итога", "tp":"тип итога",
			 "c":"заголовок итога", "h": "текст всплывающего окошка"} 
	]

}

}

Как видно в нашем примере, у нас есть связи, мы используем в качестве полей – комбобоксы, список улиц и городов. Так же в нашем примере есть итоги, но это только в качестве примера, смысловой нагрузки, в нашем случае, итоги по таблице не несут.
Далее надо подготовить описания для комбобоксов, чтобы наша таблица работала.
Описания mxl для комбо хранятся в отдельной, для этого, папке MetaXLib_cfg/dict/comboboxes

6

Создадим описание для комбо city и street


{
/** 
 * может принимать значения: 
 * 		enum  - на основе enum
 * 		db    - на основе прямой загрузки из БД
 */
"type"          : "db",

"name"          : "city",
"logicBaseName" : "orgndb",

"valueField"    : "CITY_ID",
"displayField"  : "CITY_NAME",
"emptyText"     : "Выберите город...",
"tableName"     : "city",
"where"         : "",
"order"         : "city_name ASC",
"inputTextMode" : true,
"clearedMode"   : true
}

Расшифруем значения


{
  "type"          : тип источника данных,
  "name"          : имя комбобокса,
  "logicBaseName" : имя логической БД, из которой будут браться данные,
  "tableName"     : имя таблицы в БД, из которой будут браться данные,
  "valueField"    : поле из которого будут заполняться ключевые значения,
  "displayField"  : поле из которого будут отображаться данные,
  "emptyText"     : текст который будет показан когда не задано значение,
  "where"         : условие ограничения на отбор данных из таблицы,
  "order"         : условие сортировки на данные их таблицы,
  "inputTextMode" : false/true - возможность ввода текста для фильтрации значений,
  "clearedMode"   : false/true - перевод комбо в режим работы с кнопкой очистить
  }

Небольшое отступление: в стандартной комплектации extJS у комбобокса нет кнопки для очистки значения, наша библиотека дополняет это упущение, создавая расширение класса Ext.form.ComboBox – ClearableComboBox, у которого данная кнопка есть.
По аналогии создадим описание для улиц:


  {
/** 
 * может принимать значения: 
 * 		enum  - на основе enum
 * 		db    - на основе прямой загрузки из БД
 */
"type"          : "db",

"name"          : "streets",
"logicBaseName" : "orgndb",

"valueField"    : "STREET_ID",
"displayField"  : "STREET_NAME",
"emptyText"     : "Выберите улицу...",
"tableName"     : "streets",
"where"         : "",
"order"         : "street_name ASC",
"inputTextMode" : true,
"clearedMode"   : true
}

  
Теперь создадим файл, который выведет нашу таблицу

  <?php
include_once realpath(dirname(__FILE__) . '\src\init.php');

$WGS = new mxl_widget_widgets();

$DBG1 = new mxl_widget_dbgrid('refpeoples1', 'refpeoples');
$WGS->addWidget($DBG1);
$fileName = realpath(dirname(__FILE__) . '\js_cash') . '\ref_peoples.js';
$WGS->WriteJScript($fileName);
?>

  

В html коде вставляем div


  <div  id="dbg_refpeoples1"  style="padding-left:50px"></div>

Сюда отобразится наша таблица

7

Теперь сделаем форму, в которую будет переноситься данные из выбранной строки, на текущий момент библиотека MXL не содержит инструментов для быстрого создания форм, поэтому сделаем extJS форму сами, добавим JS код:


//добавим форму для редактирования полей справочника  контактов
  var form_contact = new Ext.form.FormPanel({
  title:'Редактирование записи',
  labelAlign:'left',
  labelWidth:80,
  frame:true,
  layout:'form',
  width:360, autoHeight:true,
  style:{padding:'10px'}

 

    }); //ФИО контакта var contact_name = new Ext.form.TextField({ fieldLabel:'Ф.И.О.', name:'fio', width:250 });     //дата рождения контакта var contact_birthday = new Ext.form.DateField({ fieldLabel:'Дата рождения', name:'birthday', width:90, allowBlank:true, format:'d.m.Y h-m' });     //комбо выбора города var cbxCity = new Ext.form.ComboBox({ store:store_dbgcbx_dbg_refpeoples1_city, valueField:"city_id", displayField:"city_name", name:'city', valueNotFoundText:'-', fieldLabel:'Город', width:230, mode:"local", typeAhead:true, editable:true, minChars:0, forceSelection:false, selectOnFocus:false, listWidth:230, triggerAction:"all", emptyText:"Выберите город...", lazyRender:true     });     //комбо выбора улицы var cbxStreet = new Ext.form.ComboBox({ store:store_dbgcbx_dbg_refpeoples1_street, valueField:"street_id", displayField:"street_name", name:'street', valueNotFoundText:'-', fieldLabel:'Улица', width:230, mode:"local", typeAhead:true, editable:true, minChars:0, forceSelection:false, selectOnFocus:false, listWidth:230, triggerAction:"all", emptyText:"Выберите улицу...", lazyRender:true     });     //дом var contact_house = new Ext.form.TextField({ fieldLabel:'Дом', name:'home', width:50, vtype:'alphanum' }); //корпус var contact_corp = new Ext.form.TextField({ fieldLabel:'Корпус', name:'corp', width:50, vtype:'alphanum' }); //квартира var contact_flat = new Ext.form.TextField({ fieldLabel:'Квартира', name:'flat', width:50, vtype:'alphanum' });     //кнопка // по нажатию вызывается функция myupdateField var setButton = new Ext.Button({ text:'Установить', handler:myupdateField, style:{marginLeft:'250px'} });     //собираем форму в кучу var mCol = new Ext.util.MixedCollection(); mCol.addAll([contact_name, contact_birthday, cbxCity, cbxStreet, contact_house, contact_corp, contact_flat, setButton]);

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

dbg_refpeoples1.getSelectionModel().on('rowselect', selectGridRow);

Ну и собственно функция, которая переносит данные в форму из таблицы

    //при выборе строки переносим данные в  форму
    function selectGridRow() {
    var gr_arr =  dbg_refpeoples1.getSelectionModel().getSelected();
    form_contact.getForm().loadRecord(gr_arr);
    }
8

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


    function myupdateField() {
        //получаем строку грида как тип Record
        var gr_arr = dbg_refpeoples1.getSelectionModel().getSelected();
        form_contact.getForm().updateRecord(gr_arr);
    }

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

8

Сделаем описание для таблицы, куда будем выводить группы контактов:
refcont_in_groups.mxl


{
  "name"          : "refсont_in_groups",
  "caption"       : "Группы контакта",

 

"logicBaseName" : "orgndb", "tableName"     : "cont_in_groups", "primaryKey"    : "cig_id", "queryText"     : "", "where"         : "a.people_id=[:people_id:]", "order"         : "", "options" : { "readOnly"         : false, "validator"     : "groups", "selectByLeftJoin" : false,          "manyRowsSaveMode" : true, "paginMode"        : false, "pageStart" : 0, "pageSize" : 0,          "nextColOnEnter"   : true, "clicksToEdit"     : 1,          "height"           : 200, "width"            : 400 }, "fields" : [ {"n":"cig_id",         "c":"Код группы контакта", "w":"10", "dt":"int", "dl":"0",  "a":"|HD|",   "mr":""}, {"n":"people_id",      "c":"Код человека", "w":"10", "dt":"int",    "dl":"0",  "a":"|HD|",   "mr":""}, {"n":"cont_group_id",  "c":"Код группы", "w":"10", "dt":"int",     "dl":"0",  "a":"|HD|",   "mr":""}, {"n":"group_name",     "c":"Имя группы", "w":"50", "dt":"string",     "dl":"250",  "a":"|NU|",   "mr":""} ], "relations" : [ {"fn":"group_name", "rl":"cont_groups;d;group_name;a.cont_group_id=d.group_id", "cn":"@cbx_group_dbsql", "lw":500} ], "defaults" : [ {"fn":"people_id", "df":[:people_id:]} ] }

Обратите внимание, появилось значение where

"where"         : "a.people_id=[:people_id:]",

Значение, заключенное в [::] – ключ на которое завязывается значение, данная конструкция заменится передаваемым значением, т.е. при инициализации таблицы, можно передать параметр, как в нашем примере - people_id, со значением и он будет отработан конструктором таблицы.
Передача параметра делается следующим образом:

$DBG = new mxl_widget_dbgrid('refcont_in_groups1',
			  'refcont_in_groups', new mxl_core_params(array('people_id' => -1)), false);
Мы создаем таблицу и передаем список параметров через создание объекта mxl_core_params:
new  mxl_core_params(array('people_id' => -1)).
Тут задается значение people_id равное -1 через ассоциативный массив. Это сделано для придания гибкости формирования грида, когда требуется отображение определенных данных по условиям.
В нашем случае передаваемое значение будет отображать пустую таблицу, пока мы динамически не отошлем новое значение ключу people_id.
Теперь код инициализации таблицы групп контакта полностью:

	$DBG = new  mxl_widget_dbgrid('refcont_in_groups1', 'refcont_in_groups',
					 new  mxl_core_params(array('people_id' => -1)), false);
	$DBG->setEventHandler(mxl_widget_dbgrid::$ehtAppendRow,  'refcont_in_groups1_onRowAdd');
	$WGS->addWidget($DBG);

Обратите внимания, в коде присутствует пока непонятная нам конструкция: setEventHandler, значение ее объясним чуть позже.
Модифицируем html код:

<table>
  <tbody>
    <tr>
      <td>
        <div id="pole"  style="padding-left:50px"></div>
      </td>
      <td>
        <div  id="dbg_refcont_in_groups1"  style="padding-left:50px"></div>
      </td>
    </tr>
  </tbody>
</table>
<div id="dbg_refpeoples1"  style="padding-left:50px"></div>
  

Таким образом, мы видим уже две таблицы и одну форму на странице:

9

Теперь нам надо создать функционал, для того, чтобы при выборе строки в «Справочники: Люди» у нас отображались группы контакта, и мы могли вводить новую группу для контакта, также изучим проверку на сохраняемые данные. Итак, первое, что мы сделаем, научим таблицу групп динамически загружать данные в зависимости от выбранного человека.

Для этого чуть модифицируем функцию, которая вызывается при выборе строки в гриде, а именно selectGridRow.


  //при выборе строки переносим данные в  форму
  function selectGridRow() {
     var gr_arr = dbg_refpeoples1.getSelectionModel().getSelected();
     form_contact.getForm().loadRecord(gr_arr);
     //данный кусок динамически устанавливает параметр для  таблицы групп контактов
     if (gr_arr.data["people_id"]) {
        mxl_SetDynamicBaseParam(dbg_refcont_in_groups1.store,
							  "people_id", gr_arr.data["people_id"]);
        dbg_refcont_in_groups1.store.load();
     }  else {
        dbg_refcont_in_groups1.store.removeAll();
        form_contact.getForm().reset();
     }
  }

Мы добавили условие, если в таблице выбрана строка и значение people_id не ноль вызываем метод установки динамического параметра


 mxl_SetDynamicBaseParam(dbg_refcont_in_groups1.store, "people_id", gr_arr.data["people_id"]);

Данная процедура в качестве параметров принимает:

  1. хранилище (store) объекта (таблицы);
  2. имя динамического параметра;
  3. значение, которое в него надо установить.

После установки параметра, необходимо загрузить хранилище заново: dbg_refcont_in_groups1.store.load();
Там же мимоходом сбрасываем значения формы: form_contact.getForm().reset();
Теперь у нас при выборе контакта, автоматически заполняются группы для него, если они были внесены.
Далее возникает проблема, а что же делать, когда добавится новая строка в таблицу Справочника Люди. Тут приходит возможность переназначать обработчик событий для стандартных действий грида(таблицы). Нам необходимо создать функцию, которая будет отрабатывать нажатие кнопки + в шапке таблицы, т.е. при добавлении строки. Вот функция


  //собственный обработчик  добавления строки, на который ссылается инициализация грида
  function refcont_in_groups1_onRowAdd(event, toolEl, panel) {
    //добавляем строку в таблицу  групп контакта refcont_in_groups1
    var newRecord = new record_refcont_in_groups1({});
    var sel =  panel.getSelectionModel().getSelected();
    var selIndex = 1;
    
    if (sel)
      selIndex +=  panel.getStore().indexOf(sel)
    else
      selIndex =  panel.getStore().getCount();.
      
    panel.getStore().insert(selIndex,  newRecord);
    panel.getSelectionModel().selectRow(selIndex);
    panel.getView().focusRow(selIndex);

 

//теперь, после добавления, заменяем значение поля people_id // на значение с people_id c таблицы людей var people_id = dbg_refpeoples1.getSelectionModel().getSelected().data["people_id"]; if (people_id) { var gr_arr = dbg_refcont_in_groups1.getSelectionModel().getSelected(); gr_arr.set('people_id', people_id); //чтобы не сохранять только введнный ID // сбросим флаг модифицированности со строки gr_arr.commit(); } }

Теперь воспользуемся методом назначения собственного обработчика событию вызываемого в таблице:
Как уже указывали выше, новый метод:


  $DBG->setEventHandler(mxl_widget_dbgrid::$ehtAppendRow, 'refcont_in_groups1_onRowAdd');

В качестве параметров принимает:

  1. Тип и источник события;
  2. Имя процедуры, на которую заменяется стандартный обработчик.

Для таблицы используется префикс mxl_widget_dbgrid:: затем одно из 4х событий
нажатие кнопки обновить (изменение данных)
$ehtRefreshData
нажатие кнопки добавить (добавление новой строки)
$ehtAppendRow
нажатие кнопки Сохранить (сохранить изменение данных)
$ehtSaveData
нажатие кнопки удалить (удалить выделенную строку)
$ehtDeleteRow.

Далее мы столкнемся с проблемой, а что делать, ведь при текущем раскладе, можно в таблицу групп добавлять одни и те же группы. Для решения данной проблемы мы используем «валидацию», т.е. проверку сохраняемых данных. Производить валидацию будем на стороне сервера. Можно конечно сказать, что это быстрее и дешевле на стороне клиента, но нам нужно просто раскрыть суть «валидации», да и более правильно валидацию проводить на сервере, во избежание подделки данных.
Как возможно вы заметили, в описателе таблицы групп контактов у нас присутствует вот такая запись:
"validator"     : "groups",
Это значит, что при сохранении строки, она будет предварительно проходить валидацию, описатель которого находится в /MetaXLib_cfg/dict/validators в файле - groups.mxl, вот его содержимое:


{
  "beforeValidate" :  "",
  "afterValidate"  : "", "rules" : {
  "common"  : {
  },
  "dbgrid"  : {
  "uniqueLR"  : "cont_group_id:people_id;"
  }
  }
}

Формат описания валидатора


  "beforeValidate" : "Имя сниппета валидатора, выполняемого  перед валидацией",
  "afterValidate"  : "Имя  сниппета валидатора, выполняемого после валидации",
  
  "rules" : {
    секция общих правил - которые не требуют  знания о природе поля из описания метаданного
    "common"  : {
      правило required - проверяет набор полей  на обязательность наличия значения.
      в качестве параметра передается список  полей разделенных ';'
      "required"      : "имя поля 1; имя поля 2;"
    },
    секция правил для грида - требуют знания, по  какому гриду строится правило валидации
    "dbgrid" : {
      "check_type"  : "amount;ngroup;",
      "unique"     : "fee_id;"
      }
    }
  }

В нашем случае используется валидатор на уникальность сочетания полей в базе, чтобы не было назначено одному и тому же человеку несколько одинаковых значений групп.
Если мы попытаемся ввести в таблицу одинаковые группы и сохранить результат, получим вот такую ошибку и сохранение не удастся. Описание всех валидаторов и примеры их применения приведены в приложении.

ошибка

Далее мы рассмотрим применение сниппетов валидации результата.
Как было приведено ранее, описатель валидатора имеет два поля:


"beforeValidate" : "Имя сниппета валидатора, выполняемого перед валидацией",
"afterValidate"  : "Имя сниппета валидатора, выполняемого после валидациии",

Всего видов сниппетов валидации четыре:

beforeAllValidate – сниппет, выполняющийся до валидации всего массива измененных данных;
beforeValidate – сниппет, выполняющийся до валидации построчно;
beforeDelete – сниппет, выполняющийся перед удалением строки;
afterValidate – снипет, выполняющийся после валидации построчно;

Доступные поля в теле сниппета:

Переменная для передачи строки на проверку
array $row;

Переменная для передачи массива строк на проверку
array $rows;

Переменная для передачи значения ключевого поля
 integer $keyValue;

Доступ к переменным: $this->row, $this->rows, $this->keyValue

Особенности:
beforeDelete доступно только одно поле – keyValue, т.к. удаление идет по ID
beforeAllValidate – доступно поле rows,
для остальных доступно только row и keyValue.
Пример сниппета валидатора отрабатывающего удаление строки:



  <?php
    $mxl_ldbs = new  mxl_core_logicbases();
    $mxl_db = $mxl_ldbs->getLogicBaseInst('orgndb');
    $sql  = 'SELECT people_id , fio '
           .' FROM  peoples'
           .' WHERE people_id=13';
    $res  = '';
    $result0 = $mxl_db->sql_query($sql);
    while  ($row0 = $mxl_db->sql_fetchrow($result0)) {
      $res .= $row0['fio'];
    }
    if ($res){
      $this->result = 'Не  хочу удалять эту строчку, хоть убей :))'
                    . '<br> Значение ключевого поля: '.$this->keyValue . '  ' .  $res;
      } else {
        $this->result = true;
    }
  ?>
  

Приведенный пример немного надуманный, но он показывает следующее:
Обращаемся к базе данных и делаем выборку по условию people_id = 13, если запрос не пустой, отменяем удаление, иначе разрешим.
Для успешного прохождения валидации, валидатор должен вернуть true, в противном случае валидация считается не пройденной и выводится сообщение, которое передается в поле result.
В целом, сниппеты всех видов описываются одинаково, разница только в моменте вызова сниппета: до, после валидации или в момент удаления строки.
Размещаются сниппеты в папке /MetaXLib_cfg/dict/validators/snippet_validate. Вызов происходит по имени файла, содержащего сниппет.
Пример:


{
  "beforeValidate"  : "",
  "afterValidate"  : "",
  "beforeDelete"  : "people_beforeDel",
  …
  

В папке сниппетов валидации создается файл с именем people_beforeDel.php.

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

Общие сниппеты

Помимо сниппетов валидации, существуют сниппеты, которые обрабатываются в файлах описаний виджетов. Вид такого сниппета следующий:


"fields" : [
  {"n":"product_type",       "c":"ProductTypeID","w":"10",  "dt":"int",  "dl":"0",   "a":"|HD|",    "mr":""},
  {"n":"product_type_name", "c":"Product  Type", "w":"15", "dt":"string",  "dl":"10", "a":"|NU|",   "mr":""},
  ,  /*вот это и есть обращение к сниппету*/

Имя файла сниппета заключается в двойные квадратные скобки. Сам сниппет располагается в папке с описаниями виджетов, если например сниппет используется в таблице, тогда в папке grids создается папка snippet и там создается и хранится сниппет для таблиц, и так для любого вида виджетов. Но что же хранится в самом сниппете, вот например самое простое:


<?php
  $output = '
    {"n":"fees_group_id",     "c":"Group ID",     "w":"10",  "dt":"int",
				  "dl":"0",   "a":"|HD|",    "mr":""},
    {"n":"fee_id",            "c":"ID",           "w":"10",  "dt":"int",
			     "dl":"0",   "a":"|HD|",    "mr":""},
    {"n":"product_id",        "c":"Product ID",   "w":"15",  "dt":"int",
			     "dl":"0",   "a":"|HD|",    "mr":""},
    {"n":"product_name",      "c":"Product",      "w":"25",  "dt":"string",
				 "dl":"40",  "a":"|NU|",    "mr":""},
    {"n":"amount",            "c":"Amount  >=",     "w":"20", "dt":"int",
			    "dl":"0",  "a":"",       "mr":"",  "formatN" : "$0,000."},
    {"n":"fee",               "c":"Fee",           "w":"20", "dt":"float",
				"dl":"10",  "a":"",        "mr":"", "formatN" : "0,000.00 руб."},
    {"n":"fee_type",          "c":"Fee  Type",      "w":"25", "dt":"string",
				"dl":"10", "a":"|ENUM|",  "mr":""}
    ';
  $this->result = $output;
?> 
  

В сниппете хранится просто часть текста, которая задает параметры грида, а можно еще использовать динамические параметры, тут несколько сложнее. В сниппете доступно поле dParams, которое является ассоциативным массивом. Значения в данную переменную передаются только при инициализации виджета следующим образом:


$DBG1 = new mxl_widget_dbgrid('refpeoples1', 'refpeoples', new mxl_core_params(
    array('param1' => $value_param1)));

В сниппете наш параметр будет доступен следующим образом:


If (isset($this->dParams['param1']))  {
  Echo 'Динамический  параметр установлен';
  }

Ну а далее, можно будет распоряжаться данным параметром как угодно.
Например, вот так:


<?php
    if (isset($this->dParams['showFlat']) && $this->dParams['showFlat']  == '1') {
      $output = ',{"n":"flat",  "c":"Кв.",  "w":7, "dt":"int",  "dl":11, "a":"", "mr":""}';
      } else {
        $output = '';
      }
    $this->result  = $output;
?>
  

Результат выводится через поле $this->result.

Рендереры

  • Рассмотрим рендереры для таблицы, объявление которых находится в файле описания, в секции options:

Повторимся renderer – имя файла скрипта рендерера, расположенного в папке рендереров. Для чего он собственно нужен? С помощью рендерера мы можем подменить значения полей уже после загрузки из базы данных.
Пример простого рендерера:


<?php
    $this->row['fio'] = '55--'.$this->row['fio'];
    $this->result = true;
?>
  

При загрузке таблицы мы на выходе получим следующее:

рендер

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

рендер2

Хотя можно добавить и условие в рендерер, при соблюдении которого не будет добавляться строка, если она уже присутствует в базе.

Описание простых виджетов

 

Виджет дата-время:

дата время

Позволяет вывести поля даты и времени на странице с инструментом календарь, для удобного выбора даты. Время представлено в виде списка, с шагом в 15 минут.

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


$WG1 = new  mxl_widget_datetime('start', mktime( 0, 0,0,date('m'),date('d'),date('Y')));
  • Первый параметр: наименование, string;
  • Второй параметр: стартовое значение даты времени, int  в формате UNIX.

Вставка в HTML
Префикс ID для элементов:

  • Дата: date_field_
  • Время: time_field_

<div class="myTime">
  <div  id="date_field_start" class="date_field"></div>
  <div  id="time_field_start" class="time_field"></div>
</div>

Виджет комбобокс
Показывает поле с выпадающим списком:

combobox

Данный виджет достаточно гибкий, т.к. может быть инициализирован из 3 типов источников: перечисление, запрос к БД, прямая загрузка из БД.
Инициализация виджета:


  $WGS = new  mxl_widget_widgets();
  $WGS->addWidget(new  mxl_widget_combobox(($name, $comboName, $startValue  = '',
        	 $params  = '', $hiddenName  = '', $autoload  = true));
  

Параметры, для которых установлено значение, являются необязательными


  string $name – имя виджета;
  string $comboName – имя модели комбобокса;
  string $startValue – начальное значение ключевого  поля;
  string $params = '' – параметры инициализации,  пример:
  new mxl_core_params(array('people_id' => -1)),
			 параметры  передаются для замещения записей вида [:people_id:],
  в описателе виджета, рабочий пример приведен выше. 
  string $hiddenName – имя id элемента в который будет сохранено  результирующее значение ключевого поля;
  boolean $autoload – Определяет будет ли загрузка  происходить автоматически или вручную;

Инициализация виджета происходит через JSON файл, как было показано выше на примере таблицы и ее полей.
Пример файла инициализации комбобокса:


{
  /** 
  * может принимать значения: 
  *                    enum  - на основе enum
  *                    db    - на основе прямой загрузки из БД
  *                     dbsql - на основе запроса к  БД
  */
  "type"          : "dbsql",
  "name"          : "countries_dbsql",
  "logicBaseName" :  "db_ceifx",
  "valueField"    : "country_id",
  "displayField"  : "country_name",
  "emptyText"     : "Select country...",
  "query"         : " select country_id,  country_name from countries ",
  "where"         : "",
  "order"         : "",
  "inputTextMode" : true,
  "clearedMode"   : true
}

Как видно, параметры достаточно говорящие. Данный комбо загружается на основе запроса к БД. Остановимся на отдельных параметрах:

  • "inputTextMode" : true – в поле разрешен ввод, при вводе текста происходит автоматическое дополнение существующим значением в списке.
  • "clearedMode"   : true – справа поля добавляется кнопка, для обнуления текущего значения.
  • "emptyText"     : "Select country..." – строка, которая отображается, если не выбрано ни одно из значений списка.

Файл описания располагается по следующему пути: /MetaXLib_cfg/dict/comboboxes.
Сразу остановимся на типе источника – enum.
Файл описания enum  располагается тут: MetaXLib_cfg/core/enums
Пример файла перечисления (testEnum1.mxl):



{
  "name"    : "testEnum1", 
  "caption" :  "Заголовок перечисления 1",
  "values"  : [
    {"key"  : "val1.1", "value" : "Значение1"},
    {"key"  : "val1.2", "value" : "Значение2"},
    {"key"  : "val1.3", "value" : "Значение3"}
    ]
}

Файл инициализации комбо на основе перечисления:


  /** 
  * может принимать значения: 
  *    enum  - на основе enum
  *    db    - на основе прямой загрузки из БД
  */
  "type"          : "enum",
  "name"         : "testen",
  "valueField"   : "key",
  "displayField" : "value",
  "emptyText"    : "Пустой текст",
  "enumName"     : "testEnum1",
  "inputTextMode" : true,
  "clearedMode"   : true

"enumName"     : "testEnum1" – имя файла перечисления.

Файл инициализации комбо на основе прямого чтения из БД:


{
  /** 
  * может принимать значения: 
  *    enum  - на основе enum
  *    db    - на основе прямой загрузки из БД
  */
  "type"          : "db",
  "name"          : "city",
  "logicBaseName" : "orgndb",
  "valueField"    : "CITY_ID",
  "displayField"  : "CITY_NAME",
  "emptyText"     : "Выберите город...",
  "tableName"     : "city",
  "where"         : "",
  "order"         : "city_name ASC",
  "inputTextMode"  : true,
  "clearedMode"   : true
}

Разница между инициализации на основе запроса и прямого обращения в 2х полях:
В первом случае присутствует параметр:

"query"         : " select country_id, country_name from countries "

Во втором случае, вместо него используется:

"tableName"     : "city"

Виджет список – list
Выводит список
Вариантов списка всего два:

  • multiselect  - Список с множественным выбором
  • itemselector - Два списка с перемещением выбранных значений во второй список
list1
list2

Также, у списков есть возможность показать кнопку очистки выбранных значений

clearList1
clearList2

Инициализация виджета:


  $WGS = new  mxl_widget_widgets();
  $WGS->addWidget(new  mxl_widget_list('list1', 'lst_test'));

Список параметров, передаваемых в конструктор:

  • string $name - имя виджета (должно совпадать с именем id);
  • string $listName - имя модели списка;
  • string $params – параметры;
  • boolean $autoload - Определяет, будет ли загрузка происходить автоматически или вручную.

Пример вставки в HTML:


  <div style="padding-left:  15px">
    <span  id="list1"></span>
  </div>

Пример инициализации списка с источником данных БД:


{
  /** 
  * может принимать значения: 
  *    enum  - на основе enum
  *    db    - на основе прямой загрузки из БД
  */
  "type"          : "db",
  "name"          : "lst_test",
  /** 
  * может принимать значения: 
  *    multiselect  - Список со множественным выбором
  *    itemselector  - Два списка с перемещением выбранных значений во второй список
  */
  "kind"          : "itemselector",
  "title"         : "Список с переносом во  второй",
  "fieldLabel"    :  "Тут<br>описание<br>списка",
  "clearButton"   : true,
  "commonWidth"   : 410,
  "elementWidth"  : 130,
  "height"        : 150,
  "logicBaseName" : "orgndb",
  "valueField"    : "city_id",
  "displayField"  : "city_name",
  "tableName"     : "city",
  "where"         : "",
  "order"         : ""
}

Пример инициализации с источником данных из перечисления:


{
  /** 
  * может принимать значения: 
  *    enum  - на основе enum
  *    db    - на основе прямой загрузки из БД
  *    dflow  - на основе потока // пока не реализованно 
  */
  "type"          : "enum",
  "name"          :  "lst_feesres_enum_itemselector",
  /** 
  * может принимать значения: 
  *    multiselect  - Список со множественным выбором
  *    itemselector  - Два списка с перемещением выбранных значений во второй список
  */
  "kind"          : "itemselector",
  "enumName"     : "fees_receive_modes",
  "valueField"   : "fee_receive_mode",
  "displayField" :  "fee_receive_mode_name"
}

Структура описания практически аналогична структуре ComboBox, дополнительные параметры:
kind – multiselect, itemselector, описание приведено выше;
title ­­- ­заголовок списка;
fieldLabel – текст описания списка;
clearButton ­­– наличие/отсутствие кнопки отмена выбора.

Описание перечисления одинаково для всех виджетов и приведено выше.

Приложение

Описание атрибутов полей

|RO| – Поле будет доступно только для чтения.
|HD| – Поле будет сокрыто от пользователя, но видимость можно изменить в  визуальной части.
|NU| – Отмечаются поля, которые являются связанными полями из других таблиц, поля такого плана обновляются при выборе ключевого значения и не  редактируются напрямую. Обычно данные используются для отображения читаемого значения индекса.
|ENUM| – Отмечаются поля, выбор значений которых осуществляется при помощи комбобоксов на основе перечислений.
|CHECK| – Отмечаются поля типа int которые будут представлены в гриде в виде CheckBox. 0 - отрицательное значение, 1 – положительное.

Список валидаторов

Секция common:

Required - метод проверки полей, необходимых к заполнению.

Возвращает true в случае успешной проверки, иначе сообщение о нарушении правила.
Поля передаются через ';', если необходимо указать заголовок поля, который будет отображаться при выводе сообщений по этому полю, то в параметр задается через ':'. До ':' идет имя поля, после заголовок.
Пример:
'paramToCheck1:CaptionParam1;paramToCheck2;...'

periodMember –       Метод проверки принадлежности значений полей промежутку допустимых значений.

Возвращает true в случае успешной проверки, иначе сообщение о нарушении правила.
Проверяемые поля с границами интервала передаются через ';'. Если указывается одна из границ интервала, то сперва записывается имя поля, затем знак соответствующего неравенства, а затем значение границы. Если указываются обе границы интервала допустимых значений, то они записываются последовательно: минимальная граница, знак неравенства, имя поля, знак неравенства, максимальная граница. Проверяемые неравенства могут быть строгими (>, <) или не строгими (>=, <=).Если необходимо указать заголовок поля, который будет отображаться при выводе сообщений по этому полю, то в параметр задается через ':'. До ':' идет имя поля, после заголовок.
Пример:
'minvalue1<field1:caption1<=maxvalue1;field2<maxvalue2;field3:caption3>=minvalue3;...'

checkEMail – Метод валидации e-mail адреса.

Возвращает true в случае успешной проверки, иначе сообщение о нарушении правила.
Проверяемые поля передаются через ';', если необходимо указать заголовок поля, который будет отображаться при выводе сообщений по этому полю, то в параметр задается через ':'. До ':' идет имя поля, после заголовок.
Пример:
'paramToCheck1:CaptionParam1;paramToCheck2;...'

checkLogin – Метод валидации логина.

 Возвращает true в случае успешной проверки, иначе сообщение о нарушении правила.
Логин может содержать латинские символы, цифры, '_', '.', '-'. Первый символ логина должен быть буквой или цифрой.
По умолчанию проверяется, чтобы в логине было не менее 1 символа, но не более 20, но границы допустимых размеров строки логина могут быть заданы правилом.
Проверяемые поля с границами интервала допустимой длины строки передаются через ';'. Если указывается одна из границ интервала, то сперва записывается имя поля, затем знак соответствующего неравенства, а затем значение границы.
Если указываются обе границы интервала допустимых значений, то они записываются последовательно: минимальная граница, знак неравенства, имя поля, знак неравенства, максимальная граница.
Проверяемые неравенства могут быть строгими (>, <) или не строгими (>=, <=).
Если необходимо указать заголовок поля, который будет отображаться при выводе сообщений по этому полю, то в параметр задается через ':'. До ':' идет имя поля, после заголовок.
Пример:
'field1;field2:caption2>=minlength2;minlength3<field3<=maxlength3;...'

checkPassword – Метод валидации пароля.

Возвращает true в случае успешной проверки, иначе сообщение о нарушении правила.
Пароль может содержать любые символы, кроме кириллицы и спецсимволов (пробел, табуляция)
По умолчанию пароль может быть пустым, но не может содержать более 20 символов, но границы допустимых размеров строки пароля могут быть заданы правилом.
Проверяемые поля с границами интервала допустимой длины строки передаются через ';'.
Если указывается одна из границ интервала, то сперва записывается имя поля, затем знак соответствующего неравенства, а затем значение границы.
Если указываются обе границы интервала допустимых значений, то они записываются последовательно: минимальная граница, знак неравенства, имя поля, знак неравенства, максимальная граница.
Проверяемые неравенства могут быть строгими (>, <) или не строгими (>=, <=).
Если необходимо указать заголовок поля, который будет отображаться при выводе сообщений по этому полю, то в параметр задается через ':'. До ':' идет имя поля, после заголовок.
Пример:
'field1;field2:caption2>=minlength2;minlength3<field3<=maxlength3;...'

match – Метод валидации по регулярному выражению.

Возвращает true в случае успешной проверки, иначе сообщение о нарушении правила.
Управляющие символы, используемые в регулярном выражении, должны быть экранированы. Экранируются: одиночная кавычка ('), двойная кавычка ("), обратный слэш (\) и NULL(байт NULL).
Проверяемые поля передаются через ';'. В правиле через ':' указывается имя поля и регулярное выражение. Если необходимо указать заголовок поля, который будет отображаться при выводе сообщений по этому полю, то параметр задается через ':' после имени поля и перед регулярным выражением.
Если необходимо указать сообщение, которое будет возвращаться в случае неудачной проверки, то параметр задается через ':!' после регулярного выражения. Чтобы вставить в сообщение ссылку на поле, в нужном месте сообщения включите %f% (см. пример)
Пример:
'field1:caption1:match1;field2:match2;field3:match3:!Сообщение для поля %f%.;...'

checkType – Метод проверки типа данных и параметров полей.

Возвращает true в случае успешной проверки, иначе сообщение о нарушении правила.
Правила для проверки передаются через ';'. В правиле через ':' указывается имя поля и тип поля.
Если необходимо указать заголовок поля, который будет отображаться при выводе сообщений по этому полю, то в параметр задается через ':' после имени поля и перед типом поля.
Тип поля может принимать следующие значения: int, boolean, float, double, date, datetime, string.
Дополнительные параметры, такие как: длина строки, длина вещественной части, формат даты, указываются в круглых скобках рядом с типом поля.
По умолчанию длина строки и вещественной части чисел с плавающей точкой не имеют ограничений, формат для типа date - 'd/m/Y',
Для datetime - 'Y-m-d H:i:s'.
Пример:
'field1:int;field2:caption2:string(50);field3:double(3);field4:date(d-m-Y);...'

Секция dbgrid
Required – аналогично секции common;
periodMember – аналогично секции common;
checkType  – аналогично секции common;
checkEMail – аналогично секции common;
checkLogin – аналогично секции common;
checkPassword – аналогично секции common;
match – аналогично секции common; 

unique – Метод проверки уникальности значений полей.

 Возвращает true в случае успешной проверки, иначе сообщение о нарушении правила.
Проверяемые поля передаются через ';'.
Пример: 'paramToCheck1;paramToCheck2;...'

uniqueLR – Метод проверки уникальности комбинаций значений полей.

Возвращает true в случае успешной проверки, иначе сообщение о нарушении правила.
Проверяемые поля передаются через ';', комбинации полей разделяются ':'.
Пример:
'paramToCheck1:withCheck1;paramToCheck2:withCheck2;...'

Внимание!!! Для таблицы аналогичные методы используются без указания Caption, т.к. валидаторы таблицы не поддерживают смену заголовков. Т.е. если в секции common используется следующая конструкция (для примера взят checkType):
'field1:int;field2:caption2:string(50);field3:double(3);field4:date(d-m-Y);...', то для секции dbgrid только в виде:
'field1:int;field2:string(50);field3:double(3);field4:date(d-m-Y);...', т. caption не используется.

Список доступных виджетов

 

  • Combobox – поле с выпадающим списком;
  • dateTime – поля дата-время;
  • dbgrid – таблица;
  • list – список.

Известные проблемы

Проблема отображения виджета datetime:
При создании страницы, где по умолчанию при рендере страницы скрыта область с виджетом datetime, как например:


<div id="myID" style="display: none">
  <div id="date_field_start"  style="float: left;" class="date_field"></div>
  <div class="time_field"  id="time_field_start"></div>
</div>
  

При вызове функции, которая переведет div в состоянии display: block мы получим следующую картину:

wrongdate

Как видите, поле даты получило неверную ширину при инициализации. Решение данной проблемы является применение «костыля» сразу после генерации виджетов:


Ext.onReady(function(){
  startAutoGenScript();
  //устанавливаем  ширину контейнера
  var myEl1 = Ext.get("date_field_start");
  myEl1.setWidth(95);
});

Где «date_field_start» – ID DIV’а куда рендерится поле дата.
Важно!!!: Предварительная установка ширины div в стилях не дает ожидаемого результата.
Теперь, когда мы отобразим наш блок с датой-временем, у нас все будет в порядке.

rightdate