Form API. Создание пользовательских форм в Drupal

Опубликовано 2012.04.14

Для создания пользовательских форм очень удобно использовать встроенные в Drupal механизмы. Это гораздо удобнее, чем писать html код вручную с нуля.

Сразу даю ссылку на документацию, к которой мы будем обращаться http://api.drupal.org/api/drupal/developer!topics!forms_api_reference.html/7

Это очень удобная таблица, а также пример использования каждого элемента.

Для использования формы нужно создать функцию, которая будет возвращать массив элементов формы. Давайте сделаем несложную форму с одним полем ввода и переключателем. Каждый элемент массива $form – это элемент html формы. Каждый элемент также является массивом. Значение его ключей определяют, каким будет тот или иной элемент, как будет сформирован html код формы.

Ключ #type – это тип элемента (поле ввода, область ввода, выпадающий список, скрытое поле и т.д.).

#title –отвечает за заголовок поля

#description – описание поля

#default_value – значение по умолчанию

И так далее. Для разных типов элементов доступны свои аргументы. Смотрите документацию.

  1. //первая простая форма
  2. function my_first_form($form, &$form_state){
  3. $form=array();
  4. $form['name'] = array(
  5. '#type' => 'textfield',
  6. '#title' => t('Название поля'),
  7. '#default_value' => t('Текст по умолчанию'),
  8. );
  9. $form['settings'] = array(
  10. '#type' => 'radios',
  11. '#title' => t('Состояние статуса'),
  12. '#options' => array(0 => t('Статус 1'), 1 => t('Статус 2')),
  13. '#description' => t('Описание данного элемента.'),
  14. );
  15. $form['submit'] = array(
  16. '#type' => 'submit',
  17. '#value' => t('Submit'),
  18. );
  19. return $form;
  20. }

Чтобы отобразить эту форму – к ней нужно обратиться и отрендерить её. Для получения формы используем функцию drupal_get_form(), которой в качестве аргумента передадим id формы. Id формы совпадает с названием функции, которая возвращает массив её элементов. В нашем случае это my_first_form.

Вернемся к функции отрисовки страницы test_url - main_function.

Создадим переменную $form , которая будет содержать в себе нашу форму.

  1. function main_function(){
  2. $form = drupal_get_form('my_first_form'); //получаем поля формы
  3. $form = drupal_render($form); //рендерим форму
  4. return $form.'Содержимое тестовой страницы.';
  5. }

В 17-й строке в переменную form был помещен массив элементов формы и в 18-й этот массив отрендерен в html код. И в 19-й мы выводим эту форму.

Если всё сделано верно-то в браузере мы увидим нашу форму.

Все три поля успешно отрисованы.

Теперь обработчик формы. Для обработчика формы не требуется создавать отдельный файл, как это было с привычными html формами. Обработчиком также будет функция.

По умолчанию имя этой функции будет <id формы>_submit . Но при желании в функции формы можно задать любое другое имя.

Создадим функцию my_first_form_submit. Она будет запускаться при сабмите нашей формы. Чтобы принять данные, отправленные формой - следует обратиться к её второму аргументу - $form_state , передаваемому ей по ссылке. Но также можно использовать и стандартный массив $_POST.

Проверим работу функции, выведя на экран значение всех элементов формы.

  1. function my_first_form_submit($form, &$form_state){
  2. debug($form_state['values']);
  3. }

Обратите внимание - выводим только значение элемента с ключом values. Так как в массиве form_state  очень много ненужной нам служебной информации. Проверяем работу формы.

Заполняем форму.

И отправляем её.

Нужные нам переменные - это name и settings. Теперь мы можем записать их в файл, в БД или использовать по своему усмотрению.

Ещё у форм есть замечательный аргумент - #states. Он позволяет создавать динамические формы, без написания JavaScript кода. Например, есть следующее задание на создание формы: в форме должен быть переключатель для выбора пола (М и Ж). Если выбран Ж – то показать поле для ввода девичьей фамилии. Если выбран М – то дать возможность отметить чекбокс «Служил в армии», и если отмечен-то показать поле для ввода воинского звания.

Сейчас мы сделаем это всё тем же Form API.

Создадим новую форму с именем my_next_form. Вначале просто создадим все элементы, а потом настроим их отображение.

  1. function my_next_form($form, &$form_state){
  2. $form=array();
  3.  
  4. $form['name']=array( //Имя пользователя
  5. '#type' => 'textfield',
  6. '#title' => t('Ваше имя'),
  7. '#required' => true
  8. );
  9.  
  10. $form['sex'] = array( //пол
  11. '#type' => 'radios',
  12. '#title' => t('Ваш пол'),
  13. '#options' => array(0 => t('М'), 1 => t('Ж')),
  14. '#required' => true
  15. );
  16.  
  17. $form['maiden_name']=array( //девичья фамилия
  18. '#type' => 'textfield',
  19. '#title' => t('Ваша девичья фамилия')
  20. );
  21.  
  22. $form['served']=array( //отметка о службе
  23. '#type' => 'checkbox',
  24. '#title' => 'Служил в армии'
  25. );
  26.  
  27. $form['rank']=array( //воинское звание
  28. '#type' => 'textfield',
  29. '#title' => t('Ваше воинское звание'),
  30. '#default_value' =>t('Рядовой')
  31. );
  32.  
  33. $form['submit'] = array( //кнопка сабмит
  34. '#type' => 'submit',
  35. '#value' => t('Submit'),
  36. );
  37.  
  38. return $form;
  39. }

Также создадим новую страницу для работы с этой формой. Дадим ей адрес next_form.

  1. function test_module_menu(){
  2. $items = array();
  3.  
  4. $items['test_url'] = array(
  5. 'title' => 'Заголовок страницы',//заголовок страницы
  6. 'page callback' => 'main_function',//имя функции
  7. 'type' => MENU_NORMAL_ITEM, //тип страницы
  8. 'access callback' => TRUE, //доступ к странице
  9. );
  10.  
  11. $items['next_form'] = array(
  12. 'title' => 'Сложная форма',//заголовок страницы
  13. 'page callback' => 'form_function',//имя функции
  14. 'type' => MENU_NORMAL_ITEM, //тип страницы
  15. 'access callback' => TRUE, //доступ к странице
  16. );
  17.  
  18. return $items;
  19. }

Задаем ей новый title и главной функцией назначим функцию form_function, которую создадим далее.

  1. function form_function(){
  2. $form = drupal_get_form('my_next_form'); //получаем поля формы
  3. $form = drupal_render($form); //рендерим форму
  4. return $form;
  5. }

Очистим кэш Друпала и перейдем на URL next_form. Если не было допущено ошибок – то увидим всю форму.

Я намеренно сделал поля для имени и пола обязательными к заполнению. Как вы заметили – Drupal автоматически присвоил им нужные стили, поставил звёздочки.

Если попробовать отправить форму прямо сейчас – система выдаст сообщение о том, что поле для имени не заполнено и форма не будет отправлена. Все остальные поля сохранят свои значения (если вы их изменили).

Теперь сделаем поля зависимыми. Вначале настроим отображение поля для ввода девичьей фамилии. Дополним поле maiden_name.

  1. $form['sex'] = array( //пол
  2. '#type' => 'radios',
  3. '#title' => t('Ваш пол'),
  4. '#options' => array(0 => t('М'), 1 => t('Ж')),
  5. '#required' => true
  6. );
  7.  
  8. $form['maiden_name']=array( //девичья фамилия
  9. '#type' => 'textfield',
  10. '#title' => t('Ваша девичья фамилия'),
  11. '#states' => array(
  12. 'visible' => array(
  13. 'input[name="sex"]' => array('value' =>1),
  14. ),
  15. ),
  16. );

Аргумент states у поля maiden_name представляет собой массив. В нем может быть элемент с ключом visible или invisible, отвечающем за показ или скрытие элемента. Значением этого элемента также будет массив. Его ключ – это проверяемое значение формы, а значение этого ключа – это значение этого проверяемого значения.

Наше условие сделает элемент maiden_name видимым при условии, что значение элемента с именем sex будет равно 1.

Данного условия будет достаточно. Проверьте работу формы. Поле для ввода девичьей фамилии будет видно, только если выбран пол Ж.

Аналогично поступаем с элементом served. Только значение элемента sex должно быть равно 0.

  1. $form['served']=array( //отметка о службе
  2. '#type' => 'checkbox',
  3. '#title' => 'Служил в армии',
  4. '#states' => array(
  5. 'visible' => array(
  6. 'input[name="sex"]' => array('value' => 0),
  7. ),
  8. ),
  9. );

Теперь зададим условия для поля rank. Оно должно быть видно при условии что выбран пол М и поставлена отметка о службе в армии. Для этого в массив visible помещаем 2 элемента – 2 условия.

  1. $form['rank']=array( //воинское звание
  2. '#type' => 'textfield',
  3. '#title' => t('Ваше воинское звание'),
  4. '#default_value' =>t('Рядовой'),
  5. '#states' => array(
  6. 'visible' => array(
  7. 'input[name="served"]' => array('checked' => true),
  8. 'input[name="sex"]' => array('value' =>0)
  9. ),
  10. ),
  11. );

Проверяем форму. Выбираем женский пол и видим только поле ввода девичьей фамилии, о службе в армии и воинском звании ничего нет.

Таким образом можно создавать сложные интерактивные формы.

Также помимо обработчика форм в Drupal есть система валидации форм. Например, можно проверить – была ли введена девичья фамилия. И если не была введена – то подставить какое-то дефолтное значение. Данный функционал можно описать и в обработчике, но мы рассмотрим его в валидаторе в качестве примера.

Валидатор формы – это функция с именем <id формы> _ validate.

Создадим функцию my_next_form_validate и проверим в ней поле maiden_name. Если оно будет пустым – присвоим ему значение «Отсутствует».

  1. function my_next_form_validate($form, &$form_state){
  2. if($form_state['values']['maiden_name']==''){
  3. $form_state['values']['maiden_name']='Отсутствует';
  4. }
  5. }

Обратите внимание, что переменная form_state передаётся по ссылке.

Для проверки нашей функции валидации выведем значения полей формы в обработчике формы.

  1. function my_next_form_submit($form, &$form_state){
  2. debug($form_state['values']);
  3. }

Введем в форму только имя и нажмём Submit.

Как видите – переменная maiden_name приняла значение «Отсутствует».

Давайте ещё сделаем проверку на длину имени. Выведем ошибку, если длинна имени менее трёх символов.

  1. function my_next_form_validate($form, &$form_state){
  2. if($form_state['values']['maiden_name']==''){
  3. $form_state['values']['maiden_name']='Отсутствует';
  4. }
  5. if(mb_strlen($form_state['values']['name'])<3){
  6. form_set_error('name', t('Слишком короткое имя.'));
  7. }
  8. }

Функцией mb_strlen определим длину строки. Если она меньше трёх – то функцией form_set_error создадим ошибку. Первый аргумент этой функции – это имя поля, которое должно быть подсвечено. И второй – текст ошибки. Проверяем, пробуем ввести поле имени 1 символ.

Функция валидации успешно сработала. Форма не была отправлена.

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

Напишем обработчик.

  1. function my_next_form_submit($form, &$form_state){
  2. $name = $form_state['values']['name'];
  3. $sex = $form_state['values']['sex'];
  4. $maiden_name = $form_state['values']['maiden_name'];
  5. $rank = $form_state['values']['rank'];
  6.  
  7. $str = $name."\r\n".$sex."\r\n".$maiden_name."\r\n".$rank;
  8.  
  9. $file_name='public://'.md5(time()).'.txt';
  10. $file = fopen ($file_name,"w+");
  11. fputs ( $file, $str);
  12. fclose ($file);
  13.  
  14. drupal_set_message('Данные успешно отправлены');
  15. }

Вначале создадим 4 переменные из полученных данных. Далее объединяем их в одну переменную. Потом определим - по какому адресу будет располагаться создаваемый файл.

Строка public:// будет означать путь sites/default/files . В дальнейшем используйте её. Далее стандартными функциями PHP осуществляем запись в файл.

Теперь при каждой отправке формы будет создан файл с уникальным именем и в него будут записаны данные. И в последней строке функции  выведем сообщение пользователю о том, что форма успешно отправлена. Используем для этого функцию drupal_set_message.

Проверяем.

И открываем sites/default/files.

Файл успешно создан.

Данный пример показывает, как использовать Drupal Form API при написании кода. В реальных проектах обязательно осуществляйте проверку создания файла и записи в него. В нашем случае эти проверки не делаются, в целях минимизации кода.