====== lmbFormCommand ======
===== Общее описание =====
**lmbFormCommand** используется для огранизации работы с формами.
lmbFormCommand в конструкторе принимает:
* название шаблона, который содержит форму,
* название (идентификатор) формы,
* валидатор, который используется для проверки данных, пришедших с формы (см. [[limb3_2007_2:ru:packages:validation|пакет VALIDATION]])
* фильтр (input_filter), который используется для обработки пришедших данных:
$validator = new NewslineValidator();
$template_path = 'news/create.html';
$form = new lmbFormCommand($template_path, 'newsline_form', $validator);
lmbFormCommand содержит методы, которые позволяют получить большой спектр информации о форме:
* isSubmitted() - была ли форма отправлена или нет.
* isValid() - верны ли данные, которые пришли с формой.
* getErrorList() - возвращает объект ErrorList, который содержит список ошибок валидации, если они есть.
* getDataspace() - возвращет контейнер данных, в котором содержатся данные, пришедшие с формы. При помощи dataspace можно передавать данные в форму. Форма помещает данные из Запроса в контейнер данных только в том случае, если форма была отправлена. Класс lmbFormCommand реализован таким образом, что он поддерживает интерфейс lmbDatasource (см. [[limb3_2007_2:ru:packages:datasource|пакет DATASOURCE]]), то есть, например, можно использовать $form->import() вместо $form->getDataspace()->import().
Форма считается отправленной, если в той части Запроса, которая касается формы (если возможно несколько форм на странице), есть свойство **submitted** и оно имеет положительное значение.
===== События lmbFormCommand =====
Класс lmbFormCommand реализован с применением паттернам Observer. Он может генерировать и принимать подписку на следующие события ( в скобках указаны методы для подписки на события):
* onBefore (registerOnBeforeCallback)- при активации команды. Генерируется в любом случае.
* onShow (registerOnShowCallback)- когда форма была отображена в первый раз (то есть не была отправлена).
* onBeforeValidate (registerOnBeforeValidateCallback)- когда форма была отправлена, генерируется перед валидацией данных.
* onValid (registerOnValidCallback)- когда форма была отправлена и все данные верны.
* onNotValid (registerOnNotValidCallback)- когда форма была отправлена и данные неверны.
* onAfterValidate (registerOnAfterValidateCallback)- когда форма была отправлена, генерируется после валидации вне зависимости от результатов валидации.
* onAfter (registerOnAfterCallback)- в конце работы формы. Генерируется в любом случае.
Например, если форма была отправлена и все данные верны, то последовательно будут активизированы следующие подписчики: onBefore, onBeforeValidate, onValid, onAfterValidate, onAfter. Если формы была отображена в первый раз - то onBefore, onShow, onAfter.
===== Взаимодействие View c Controller в лице lmbFormCommand =====
Как данные из формы попадают в шаблон ([[View]])? Мы полагаем, что вы кратко ознакомились со схемом организации [[View]] и представляете, для чего нужен [[lmbView]] и [[lmbRenderer]].
Итак, первое - мы указываем название шаблона, который будет отрендерен после выполнения команды. Если вы используете шаблонную систему WACT (lmbWACTRenderer), значит внутри этого шаблона должен находиться компонент формы с идентификатором, совпадающим с названием формы, которое мы передали в конструктор lmbFormCommand.
Далее, во время выполнения lmbFormCommand команда самостоятельно передает во View свои данные и ошибки валидации, если они есть. А уже сам lmbWACTRenderer перенесет эти данные в компоненты шаблона.
Если вы не используете lmbWACTRenderer, то схема переноса этих данных может отличаться.
===== Пример использования lmbFormCommand =====
В качестве примера использования класса lmbFormCommand, приведем команду EditNewsCommand из CRUD приложения, которое идет в поставке с пакетом WEB_APP (ниже будут даны подробные комментарии):
lmb_require(LPKG_WEB_APP_DIR . '/src/command/lmbFormCommand.class.php');
lmb_require(LPKG_DBAL_DIR . '/src/lmbTableGateway.class.php');
class lmbEditNewsCommand extends lmbFormCommand
{
protected $db_table;
protected $newsline_id;
function __construct()
{
parent :: __construct($template_path = 'news/edit.html',
$form_id = 'news_form',
$validator = new lmbHandle(LPKG_WEB_APP_DIR . '/examples/crud/src/validator/lmbNewsValidator'));
$this->db_table = new lmbTableGateway('news');
$this->registerOnBeforeCallback($this, 'guard');
$this->registerOnShowCallback($this, 'init');
$this->registerOnValidCallback($this, 'updateOrPreview');
}
function guard($form)
{
if(!$this->newsline_id = $this->request->getInteger('id'))
{
$this->performCommand(LPKG_WEB_APP_DIR . '/src/command/lmbSet404ErrorViewCommand');
$form->halt();
}
}
function init($form)
{
if(($newsline_record = $this->db_table->selectRecordById($this->newsline_id)))
$form->import($newsline_record->export());
else
{
$this->performCommand(LPKG_WEB_APP_DIR . '/src/command/lmbSet404ErrorViewCommand');
$form->halt();
}
}
function updateOrPreview($form)
{
if($form->get('edit'))
{
$this->db_table->updateById($this->newsline_id, $form->export());
$this->response->redirect('/');
}
elseif($form->get('preview'))
{
$this->setToView('show_preview', true);
}
}
}
?>
Теперь разберем все очень подробно:
class lmbEditNewsCommand extends lmbFormCommand
{
[...]
function __construct()
{
parent :: __construct($template_path = 'news/edit.html',
$form_id = 'news_form',
$validator = new lmbHandle(LPKG_WEB_APP_DIR . '/examples/crud/src/validator/lmbNewsValidator'));
[...]
}
}
EditNewsCommand наследуется от lmbFormCommand и передает в родительский конструктор путь до шаблона, где определена форма, название формы //news_form// и валидатор NewsValidator (вернее [[limb3_2007_2:ru:packages:classkit:lmb_handle|хендл]] на валидатор).
function __construct()
{
[...]
$this->registerOnBeforeCallback($this, 'guard');
[...]
}
function guard($form)
{
if(!$this->newsline_id = $this->request->getInteger('id'))
{
$this->performCommand(LPKG_WEB_APP_DIR . '/src/command/lmbSet404ErrorViewCommand');
$form->halt();
}
}
Мы регистрируем слушателя на активацию формы (событие onBefore). Активация формы происходит каждый раз, когда вызывается метод lmbFormCommand :: perform(). Слушатель - это callback, который вызовает метод guard() самого класса EditNewsCommand. В методе guard мы проверяем наличие параметра id в Запросе. Если его нет, то вызывается команда lmbSet404ErrorViewCommand, которая поставит шаблон 404 ошибки, плюс при помощи метода halt() мы завершаем выполнение команды.
function __construct()
{
[...]
$this->registerOnShowCallback($this, 'init');
[...]
}
function init($form)
{
if(($newsline_record = $this->db_table->selectRecordById($this->newsline_id)))
$form->import($newsline_record->export());
else
{
$this->performCommand(LPKG_WEB_APP_DIR . '/src/command/lmbSet404ErrorViewCommand');
$form->halt();
}
}
Мы регистрируем слушателя на первоначальное отображение формы (событие onShow), который заключается в вызове метода init() самого класса команды EditNewsCommand. В методе init мы при помощи [[limb3_2007_2:ru:packages:dbal:lmbTableGateway|lmbTableGateway]] (db_table), загружаем данные о новости в контейнер данных формы. Если данных в базе данных нет, то вызывается команда lmbSet404ErrorViewCommand, которая поставит шаблон 404 ошибки, также мы завершаем выполнение команды.
function __construct()
{
[...]
$this->registerOnValidCallback($this, 'updateOrPreview');
[...]
}
function updateOrPreview($form)
{
if($form->get('edit'))
{
$this->db_table->updateById($this->newsline_id, $form->export());
$this->response->redirect('/');
}
elseif($form->get('preview'))
{
$this->setToView('show_preview', true);
}
}
Мы регистрируем слушателя на событие onValid, которое генерируется формой, когда она была отослана пользователем и все данные, которые необходимо было проверить при помощи валидатора, успешно прошли валидацию.
Метод updateOrPreview() проверяет, пришло ли поле "edit" с формы. Если пришло, это значит, что пользователь нажал на кнопку "edit" и запись в базе данных нужно обновить. После этого пользователь перебрасывается на главную страницу. Если же пришло поле "preview", значит пользователь нажал на кнопку "Preview" и необходимо показать зону шаблона preview. Для этого во [[View]] устанавливается переменная "show_preview". Сам шаблон самостоятельно решит, что делать с этой переменной. (см. [[limb3_2007_2:ru:tutorials:basic|базовый туториал]])
Некоторым разработчикам использование слушателей может показаться слишком сложным. Однако это гарантирует легкое повторное использование кода, гибкость и широкие по возможности расширению команд.