====== Декларативное описание набора строк rowset ====== [[start:|lss]] ===== Введение ===== [[rowset-definition]] - **XML** описание, по которому строются экземпляры наборов строк, привязанные к экранной форме. Описание [[rowset|набора строк]] – это описание поддерживаемых им запросов и список полей. ===== Подробнее ===== При создании [[rowset|набора строк]] на клиенте у сервера запрашивается его описание. [[rowset-definition]] запрашивается у сервера 2 раза * Первый раз описание запрашивается у [[Datasource|источника данных]]. Возвращаемое им описание не привязано к контексту использования, в нем отсутствуют связи с другими [[rowset|наборами строк]]. * Второй раз описание берется из описания экранной формы, в которой [[rowset|набор строк]] расположен. Это описание имеет более высокий приоритет, оно подстраивает работу [[rowset|набора строк]] к контексту использования внутри экранной формы. Тут задается взаимодействие с другими [[rowset|наборами строк]], расположенными в этой экранной форме. Ориентировочный вид [[rowset-definition|декларативного описания]] таков: js_refresh="" parent.row.type="<допустимый row.type узла родительского набора строк>" parent.sync.row.type="<допустимые дочерние типы узлов через ;>" parent.sync.field.icon="<имя поля, задающего иконку синхронизируемого узла>" parent.sync.field.empty="<имя поля, задающего признак row.empty синхронизируемого узла>" parent.sync.field.final="<имя поля, задающего признак row.final синхронизируемого узла>" anketa="0|1" filter="0|1" filter.autorefresh="1|0" paginator.count="0|<кол-во строк в странице>" row.focus.id="" row.focus.path="" evt_onnavigate="<имя запроса>" js_onnavigate="" mark.rowset="<имя источника данных для хранения пометок>" mark.rowset.fieldmark="<имя поля для id пометки>" mark.rowset.fieldtype="<имя поля для row.type>" mark.all="0|1 (пометить все после первого refresh)" > ...
... ... ... ... ... ... ... ... id1,id2,id3,...,idN
Список дочерних наборов строк
==== Атрибуты набора строк ==== Атрибуты набора строк имеют следующий смысл: * **readonly** - если параметр равен 1 то набор строк нельзя править. Часто формируется внутри скрипта источника данных, исходя из информации о правах текущего пользователя. * **filter** - если 1, то набор строк используется как фильтр, задающий условия для дочерних наборов строк. Его особенности: * Никак напрямую не взаимодействует с сервером (на сервере ему не соответствует никакого источника данных) * Полностью описывается в экранной форме * Всегда корневой: не может иметь родительского набора строк * Содержит одну и только одну строку, запрещена вставка и удаление строк * Значения полей проинициалезированны параметрами default из описаний полей * На каждое изменение любого поля автоматически производится перечитка дочерних наборов строк, такое поведение можно отменить параметром filter.autorefresh=0 ==== Секция ==== Секция предназначена для описания кода JavaScript функций, нужных для вычисления динамических выражений. Обычно бывает ненужна. ==== Секция ==== Секция предназначена для описания поддерживаемых источником данных запросов. Там должны быть перечислены все допустимые для источника данных запросы. Единственное исключение - запрос **request name="change"** может быть описан внутри поля, изменение которого должно инициализировать выполнение этого запроса. В описании запроса используются следующие атрибуты: * **name|request** - имя запроса * **enabled** – доступность выполнения запроса, по умолчанию доступно * **js_ensbled** – выражение JavaScript динамически определяющее доступность выполнения запроса для текущего контекста. * **icon** - иконка для обозначения операции Передаваемые запросу параметры описываются в секциях **** запроса. Особым образом обрабатываются параметры секции **** набора строк. Описанные там параметры передаются всем запросам, и их описания имеют **более высокий** приоритет, чем описание параметров внутри запроса. Эту секцию добно использовать для подстройки поведения набора строк под контекст использования в экранной форме. Атрибуты узла **** имеют следующий смысл: * **name|param** – имя параметра * **value** - значение параметра * **js_value** – выражениена JavaScript, позволяющее динамически вычислить значение параметра по контексту. * **type** - тип для приведения Для упрощения описания источника данных, при объявлении параметров действуют следующие умолчания: * Значение **id="id текущей строки"** всегда автоматически вычисляется и передается запросу, его не надо специально объявлять. * Для запроса **save** значения отредактированных и еще пока не сохраненных полей, текущей строки источника данных, автоматически вычисляются и передаются в запрос, их не надо специально объявлять. * Для передачи запросу значения поля текущей строки источника данных достаточно в атрибуте **name** указать **имя поля**, а **js_value** не указывать. Запрос **change** описывается внутри поля, при изменении которого вызывается. Его не нужно описывать в списке операций. Ему всегда передается текущее значение поля, в котором он объявлен ==== Описание полей источника данных ==== **Имя поля** задается значением атрибута **field** Рассмотрим особенности реализации типов данных для полей: * **string** – строка, просмотр и редактирование однострочным редактором * **memo** – многострочная строка * **num** – число в LSS формате * **date** – дата в LSS формате * **check** – логическое значение в LSS формате * **refname** – поле выбирается из справочника, для описания необходимо задать **refid** – имя поля ссылки на строку справочника и **refname** – имя поля внутри справочника. * **refid** – поле ссылки на строку справочника. Обязательно должен присутствовать дочерний узел **** с описанием обращения к источнику данных (запрос **request="select"**), возвращающего строки справочника. * **multilist**, **multicheck** – поле содержит значения ссылок на строки справочника, через запятую. * допустимые значения могут быть заданы параметром **list** в виде: id1=value1;id2=value2;id3=value3;...;idN=valueN * допустимые значения могут быть заданы параметром **listfield**, содержащем имя поля, в котором хранятся значения в виде: id1=value1;id2=value2;id3=value3;...;idN=valueN * допустимые значения могут быть заданы посредством дочернего узла **** с описанием обращения к источнику данных (запрос **request="refresh"**), возвращающего строки справочника. Используются параметры: **refname**, **reftext** * допустимые значения могут быть заданы параметром **listrowset**, содержащим имя источника данных, содержащего начитанные значения. Используются параметры: **refname**, **reftext**. Атрибут **visible** задает значение по умолчанию для видимости поля во всех строках. Если параметр не задан, то считается 1 (поле видимо). Если видимость поля зависит от контекста, то в атрибутах конкретного поля внутри конкретной строки можно задать параметр **visible**, который перешибет в этой строке значение, заданное для всей колонки. Атрибут **readonly** задает доступность колонки для редактирования по умолчанию. Если возможность правки поля зависит от контекста, то в атрибутах конкретного поля внутри конкретной строки можно задать параметр **readonly**, который перешибет в этой строке значение, заданное для всей колонки. Атрибут **notnull** задает требование непустого значения для поля. Атрибут **save**="1" - принудительное сохранение строки при изменении поля ==== Раздел autoexec ==== Этот раздел позволяет периодически вызывать указанный в разделе запрос ... Описание параметров * **enabled**="1|0" - по умолчанию включен, позволяет заблокировать autoexec * **request**="<имя запроса>" - выполняемый запрос, обычно refresh или refreshrow, но можно любой другой, например объявленный на уровне формы * **ignoreerror**="0|1" - по умолчанию выключен, позволяет игнорировать ошибки сервера, возникающие при выполнении запроса * **mode** - способ управления вызовом запроса === mode=timeout === В этом режиме запрос вызывается периодически, через каждые **timeout** секунд === mode=polling === В этом режиме запрос вызывается по указанию сервера, longpolling. Для реализации такого способа достаточно Apache + PHP, оповещение работает по http Клиент создает и держит с сервером продолжительное, заданное параметром **timeout** (30-300 секунд) http соединение. Сервер периодически, например раз в секунду, проверяет наличие интересующего клиента события. При возникновении события, возвращает клиенту строку **1** и завершается. Если за заданное **timeout** время событие не возникло, то серверное соединение завершается, ничего не сообщая клиенту. А клиент повторно создает новое соединение и ждет ответа. ... * url - http адрес polling соединения * timeout - время ожидания для polling соединения * параметры param - добавляются в url polling запроса **Пример реализации polling сервиса на PHP** test()) { $result=1; break; } sleep(1); } return $result; } /** Проверка возникновения события * * @return boolean наличие интересующего клиента события */ protected function test() { return false; } } return new ServiceAutoExecPolling(); Некоторые важные особенности реализации для PHP: * На входе в сервис автоматически приходит параметр timeout - время выполнения в секундах. Под него сервис должен подстроиться * Необходимо предотвратить остановку работы PHP скрипта Apache по max_execution_time, для этого max_execution_time должно быть больше, чем timeout * Необходимо останавливать PHP скрипт при разрыве соединения с клиентом. Для этого надо тестировать наличие соединения, пытаясь отправить клиенту сообщения. Пустое сообщение достаточно для тестирования соединения. * При возникновении события надо послать клиенту 1 и остановить выполнение PHP скрипта * При превышении времени необходимо остановить работу PHP скрипта, ничего не отправляя клиенту === mode=socket === В этом режиме запрос вызывается по указанию сервера, через WebSocket. Для реализации такого способа необходим сервер, поддерживающий socket соединение, технологии PHP+Apache недостаточно. Например, на PHP такой сервер можно написать на Ratchet, но это будет отдельный сервис, работающий независимо от Apache. ... * url - адрес socket соединения * pingtimeout - если параметр задан, то клиент будет периодически посылать сообщение ping серверу, для проверки соединения * параметры param - добавляются в url polling запроса Пример реализации WebSocket сервера на Ratchet clients = new \SplObjectStorage; } public function onOpen(ConnectionInterface $conn) { $queryString = $conn->httpRequest->getUri()->getQuery(); parse_str($queryString, $info); $conn->info=$info; $this->clients->attach($conn); echo '- open'."\n"; } public function onClose(ConnectionInterface $conn) { $this->clients->detach($conn); echo '- close'."\n"; } public function onMessage(ConnectionInterface $from, $msg) { if ($msg=='ping') { $from->send('pong'); echo '- ping - pong'."\n"; } } public function onError(ConnectionInterface $conn, \Exception $e) { $conn->close(); echo '- error'."\n"; } public function broadcast($msg) { echo '- отправка сообщений всем пользователям'."\n"; foreach ($this->clients as $client) { $client->send($msg); } } } $loop = Factory::create(); $serverComponent = new MyServer(); $loop->addPeriodicTimer(5, function() use ($serverComponent) { $serverComponent->broadcast('1'); }); $webSock = new React\Socket\Server('0.0.0.0:8080', $loop); $server = new Ratchet\Server\IoServer( new HttpServer( new WsServer($serverComponent) ), $webSock, $loop ); echo "\n".'WebSocket запущен'."\n"; $loop->run();