Содержание
lmbFormCommand
Общее описание
lmbFormCommand используется для огранизации работы с формами.
lmbFormCommand в конструкторе принимает:
- название шаблона, который содержит форму,
- название (идентификатор) формы,
- валидатор, который используется для проверки данных, пришедших с формы (см. пакет 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 (см. пакет 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 (вернее хендл на валидатор).
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 мы при помощи 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». Сам шаблон самостоятельно решит, что делать с этой переменной. (см. базовый туториал)
Некоторым разработчикам использование слушателей может показаться слишком сложным. Однако это гарантирует легкое повторное использование кода, гибкость и широкие по возможности расширению команд.

Обсуждение