Документация InstantCMS

для администраторов и разработчиков

Инструменты пользователя

Инструменты сайта


dev:controllers:forms

Работа с формами

InstantCMS включает механизм для быстрой разработки форм, заполняемых пользователем на сайте.

Механизм работы с формами позволяет упростить и автоматизировать:

  • создание форм;
  • вывод форм в шаблонах;
  • получение данных из формы в массив переменных;
  • проверку полученных значений (валидацию);
  • сохранение заполненных полей при повторном показе форме.

На этой странице рассмотрена только работа с формами из контроллера, то есть их подключение. Внутреннее устройство самих форм рассмотрено в соответствующем разделе.

Файлы и папки

Каждая форма принадлежит конкретному контроллеру и хранится в отдельном файле. Файлы форм находятся в папке forms внутри папки контроллера. Название файла определяется по принципу: form_{название формы}.php.

Например, форма добавления нового товара в frontend-контроллере компонента shop может называться item_add. Однако, если мы собираемся с помощью одной и той же формы делать не одно действие, например, не только добавлять в базу новый товар, но и редактировать имеющиеся, имеет смысл назвать файл и класс, описывающий форму, более универсально:

/system/controllers/shop/forms/form_item.php

Подробное описание содержимого этого файла находится в соответствующем разделе.

Загрузка формы

Внутри контроллера форма может быть загружена при помощи метода getForm($form_name[, $params]), который принимает три аргумента:

  1. Название формы
  2. (необязательный) Массив параметров в виде пар 'Название' ⇒ 'Значение'
  3. (необязательный) путь, относительно директории контроллера. Например вы решили хранить некие формы в отдельной директории /system/controllers/shop/my_folder/forms/. В этом случае в третий аргумент нужно передать my_folder/.

Например, чтобы подключить форму без параметров в контроллере компонента shop:

$form = $this->getForm('item_add');

В результате, в переменную $form попадёт объект класса cmsForm, структура которого уже должна быть нами описана в файле /system/controllers/shop/forms/form_item_add.php

Форма может менять свою структуру в зависимости от определённых условий. Например, одна и та же форма может использоваться и для создания записи в БД, и для редактирования. При этом, часть полей в форме может иметь смысл только при создании записи, а при редактировании этих полей быть не должно. Чтобы форма могла узнать контекст вызова, ей можно передать дополнительные параметры:

$form = $this->getForm('item_add', array('do' => 'add'));

или

$form = $this->getForm('item_add', array('do' => 'edit'));

Массив параметров может быть любым, мы сами определяем интерпретацию, разрабатывая шаблон для вывода формы. В файле, где мы опишем шаблон формы, эти параметры InstantCMS положит в одноимённые переменные (в данном случае, в переменную $do), благодаря чему, они могут быть использованы нашей программой для изменения структуры формы, с помощью конструкций, подобных нижеследующей:

if ($do == 'edit') { ...

Ниже этот приём будет использован в контексте разработки экшена.

Чтобы дополнительные параметры были доступны в файле описания формы в виде переменных, они должны быть объявлены, как аргументы для метода init():

public function init($do=false) { ... 

Вывод формы в шаблоне

Внутри шаблона контроллера форма может быть выведена при помощи метода

$this→renderForm($form[, $data, $attributes])

Например, экшен редактирования товара в контроллере компонента shop подготавливает параметры и вызывает форму, описанную в файле form_item.php:

public function actionItemEdit($id){
 
    // Загрузка товара из базы
    $item = $this->model->getItem($id);
 
    // Загрузка формы
    $form = $this->getForm('item_edit');
 
    // Передача товара и формы в шаблон
    $this->cms_template->render('item_edit', array(
	'do'   => 'edit',
        'item' => $item,
        'form' => $form
    ));
}

Шаблон в файле /templates/default/controllers/shop/form_item.tpl.php (в данном примере, он общий и для добавления, и для изменения товара) выведет запрошенную форму с переданными параметрами/данными в окно контроллера (компонента):

<?php 
    // Выясняем: зачем мы выводим форму?
    if ($do == 'add')  { $page_title = 'Добавление товара'; }	
    if ($do == 'edit') { $page_title = 'Изменение товара';  }
 
// Выводим теперь в окне контроллера заголовок, соответствующий задаче формы
?><h1><?php echo $page_title ?></h1>
 
<?php    
    $this->setPageTitle($page_title); // Ту же информацию выводим
                                      // в заголовок окна/вкладки браузера
 
    // Всё готово, чтобы "нарисовать" форму с соответствующими данными
    // (для 'add' это будут значения по умолчанию, для 'edit' – данные из БД)
    $this->renderForm($form, $item, array(
        'method' => 'post', // Метод передачи данных из браузера на сервер.
        'action' => ''      // Указание: какой программе передать данные пользователя из формы;
                            // '' (пустая строка) означает: их надо вернуть вызвавшему экшену.
    ), $errors);
 
    // Здесь, после вывода формы, можно выводить ещё какую-то информацию, 
    // если этого требует логика вашего веб-приложения...
?>

Получение данных из формы

До сих пор мы обращали внимание на способ выведения формы, предъявления её пользователю. Но это нужно не само по себе, а чтобы пользователь ввёл свои данные. Теперь надо разобраться: как забрать введённую пользователем информацию из формы, проверить её корректность и сохранить в базу данных?

Обратите внимание на строку в предыдущем листинге:

        'action' => '' // Указание: на какой URL передать данные пользователя из формы;
                       // '' (пустая строка) означает: их надо вернуть вызвавшему экшену, т.е. текущему URL.

Эта конструкция означает, что один и тот же фрагмент программы как выводит форму, так и забирает (анализирует) данные. То есть, этот экшен будет минимум дважды выполнен! Отличить – на каком «проходе» находится наша программа – позволяет специальная функция, определяющая – была ли в форме нажата кнопка submit? На этой кнопке в русскоязычных приложениях обычно написано «Сохранить» или «Отправить». Благодаря этой функции, на первом (выводящем форму) проходе действия по получению и проверке данных мы будем игнорировать, а на втором – выполнять. Чуть ниже мы познакомимся с этим методом.

Для получения данных, переданных из формы, в InstantCMS 2 используется метод parse() экземпляра класса формы (отсюда выражение «парсить данные», т.е. получать и раскладывать по полочкам-переменным информацию):

$form→parse($request[, $is_submitted, $item])

Но, чтобы что-то парсить, надо убедиться, что данные уже отправлены из браузера клиента в наш экшен на сервере.

Для извлечения (запроса) информации из разных объектов (в том числе, из формы), в InstantCMS 2 имеется класс, который так и называется «запрос» – request. Этот класс имеет метод has, позволяющий определить: был ли инициализирован объект, переданный в качестве аргумента? Вот, как проверяется в форме поле-кнопка 'submit':

    $is_submitted = $this->request->has('submit');

Теперь движок точно знает – выводит он сейчас форму или форма уже пообщалась с пользователем, и экшен вызвало нажатие на кнопку 'submit'? А следовательно, можно принять решение о необходимости парсить данные, складывая их в структуру $data:

    // Если форма была отправлена
    if ($is_submitted) {
        // Получаем (request) и парсим (parse) данные из формы
        $data = $form->parse($this->request, $is_submitted);
    }

Валидация формы

Как показано в соответствующем разделе, при создании структуры формы, мы можем каждому элементу управления придать некоторый набор правил: «обязательное», «максимальная длина строки», «не больше/не меньше определённого значения» и другие (полный список возможных правил см. в конце главы «Формы»).

Правила эти нужны для того, чтобы можно было проверить корректность действий пользователя, заполнившего форму. Именно на данном этапе и можно провести такую проверку – валидацию (от лат. validus ≈ здоровый, годный)

Для валидации данных, введённых пользователем, в соответствии с правилами, указанными при создании формы, используется метод экземпляра класса формы validate:

$form→validate($controller, $data[, $is_check_csrf])

// Кнопка 'Сохранить' нажата? 
$is_submitted = $this->request->has('submit');
 
// Если форма была отправлена
if ($is_submitted) {
 
    // Получаем и парсим данные из формы
    $data = $form->parse($this->request, $is_submitted);
 
    // Проверяем данные (валидация)
    $errors = $form->validate($this, $data);
    // Если в форме найдены ошибки, 
    //               то $errors будет содержать массив вида 'поле' => 'текст ошибки'
    // Если ошибок нет, $errors будет содержать false
}

В качестве итога главы о программировании форм контроллерах InstantCMS 2, покажем, как может выглядеть экшен изменения сведений о товаре в контроллере компонента shop:

public function actionItemEdit($id){
 
    // Загружаем товар из базы
    $item = $this->model->getItem($id);
 
    // Загружаем структуру формы (см. главу "Формы")
    $form = $this->getForm('item_edit');
 
    //  Кнопка 'submit' нажата?
    $is_submitted = $this->request->has('submit');    
 
    if ($is_submitted) {
        // Следующие действия будут выполнены только если данный код был вызван,
        // в ответ на отправку формы из шаблона на сервер:
 
        // Получение и парсинг данных из формы
        $data = $form->parse($this->request, $is_submitted);
 
        // Валидизируем данные
        $errors = $form->validate($this, $data);
        // Если в форме найдены ошибки, 
        //               то $errors будет содержать массив вида 'поле' => 'текст ошибки'
        // Если ошибок нет, $errors будет содержать false
 
        // Если форма прошла валидацию
        if (!$errors) {
 
            // Сохраняем изменённые данные в базе данных
            $this->model->saveItem($id, $data);
 
            // Перенаправляем на просмотр изменённого товара
            $this->redirectToAction('view', array($id));
        }
    }
    // Здесь мы окажемся либо на первом проходе, когда форма только
    // выводится пользователю первый раз,
    // либо, если форма не прошла валидацию, следовательно
    // не получилось перенаправления на страницу просмотра.
    // В обоих случаях, логично дать пользователю поработать
    // с формой (возможно, не первый раз) и отправить её на сервер.
 
    // Передача товара из формы в шаблон
    $this->cms_template->render('item_edit', array(
	'do'     => 'edit',
        'item'   => $item,
        'form'   => $form,
        'errors' => $errors
    ));
}

Вернуться к оглавлению

dev/controllers/forms.txt · Последние изменения: 04.04.2017 14:42 — fuze