====== 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|базовый туториал]]) Некоторым разработчикам использование слушателей может показаться слишком сложным. Однако это гарантирует легкое повторное использование кода, гибкость и широкие по возможности расширению команд.