Захотелось немного обобщить и так уже известные всем вещи. Но для, тех кто только начал знакомить с формами drupal (Forms API), материал будет полезен.
Вместо введения
Любая форма, созданная в drupal методом drupal_get_form, становится благодаря зацепкам в каком то смысле общедоступным объектом. Возможна произвольная модификация начального объявления, добавление обработчиков событий, добавление полей и т.п.
Типично, форма объявляется в виде некой функции, которая возвращает массив описания этой формы. Пример можно посмотреть тут. Вы можете, зная имя функции формы, объявленной в любом установленном модуле, собрать HTML код этой формы, вызвав drupal_get_form(‘имя функции-конструктора формы’). Нужно всего лишь вставить вызов этой функции в нужное место вашего кода.
Конструктор формы
Для создания собственной формы, её описание нужно выполнить в виде функции. В этой функции вы составляете массив описания формы, а в конце возвращаете этот массив как результат работы. Каждое свойство формы, её элементы — это отдельные поля массива. При этом элементы формы — тоже описываются массивом свойств.
1 2 3 4 5 6 7 8 |
function demo_form() { //далее "demo_form" повсюду будет воспринято drupal //как FORM_ID или имя формы. $form = array(); $form['field1'] = array( ... ); $form['field2'] = array( ... ); $form['#prefix'] = '<p>Наша демо форма</p>'; } |
Свойства формы и свойства полей начинаются с символа #. Описание допустимых имен свойств и случаи их применения детально описаны здесь. А я расскажу о наиболее интересных моментах (с моей точки зрения).
Вставка произвольного кода HTML. Все элементы формы (в том числе и сама форма) может иметь свойства — #prefix и #suffix. Их значение можно установить строкой с произвольным HTML кодом. Помимо этого, элементы формы неопределенного типа (когда не задано свойство ‘#type’) принимают тип по умолчанию — markup, значение (#value) которого передаётся напрямую в HTML в том месте, где расположен элемент на форме.
1 2 3 |
$form['just_html'] = array( '#value' => '<b>' . 't('Bolded text.') . '</b>', ); |
Загрузка списка автозаполнения. Некоторыми полями поддерживается свойство -‘#autocomplete_path’. Здесь можно указать путь до ajax функции (страницы на сайте), которая возвращает набор вариантов для автозаполнения. Простейший пример — показать список подходящих названий публикаций при заполнении текстового поля.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
/* какая то форма */ function demo_form() { $form = array(); $form['demo_node'] = array( '#type' => 'textfield', '#title' => t('Выберите статью по названию'), '#maxlength' => 60, '#autocomplete_path' => 'demo/autocomplete', ); return $form; } /* функция с вариантами для автозаполнения */ function _demo_autocomplete($string = '') { $matches = array(); //выбираем 10 публикаций, содержащий в заголовке название, вводимое пользователем $res = db_query("SELECT nid, title FROM node WHERE title LIKE '%" . mysql_escape_string($string) . "%' ORDER BY title LIMIT 10"); while ($r = db_fetch_object($res)) { // Add a class wrapper for a few required CSS overrides. $matches[$r->title . " [nid:{$r->nid}]"] = '<div>'. $r->title . '</div>'; } //далее рулит агент Джонсон :) drupal_json($matches); } /* в зацепку menu включаем страницу для обработки ajax запроса */ function demo_menu() { $items = array(); //cтраница для ajax вызова $items['demo/autocomplete'] = array( 'title' => 'Nodereference autocomplete', 'page callback' => '_demo_autocomplete', 'type' => MENU_CALLBACK ); return $items; } |
Использование fieldset. У некоторых вызывает сложность объявить в своей форме fieldset. Достаточно посмотреть один пример объявления, чтобы понять как это делается.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//тут мы объявляем fieldset, по умолчанию он развернут - #collapsed - false $form['fieldset_demo'] = array( '#type' => 'fieldset', '#title' => t('Some settings'), '#weight' => 5, '#collapsible' => TRUE, '#collapsed' => FALSE, ); //а это поле мы объявим внутри набора полей $form['fieldset_demo']['field1] = array( '#value' => 'Этот код будет внутри fieldset' ); |
События формы
В друпале можно установить обработчик(и) для проверки данных формы и обработчик(и), выполняющийся после всех проверок при окончательной отправке данных. Имя соответствующих функций добавляется в массив обработчиков при описании формы.
$form[‘#submit’] = array(‘demo_form_submit’);
$form[‘#validate’]= array(‘demo_form_validate’);
Обработчики можно добавить и позднее, перехватив объявление формы с помощью зацепки hook_form_alter(&$form, $form_state, $form_id); есть также зацепка по имени определенной формы hook_form_FORMID_alter, где FORMID — это имя функции-конструктора формы.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
function mymodule_form_alter(&$form, $form_state, $form_id) { switch ($form_id) { ... case 'demo_form': $form['#submit'][] = 'demo_form_submit'; $form['#validate'][] = 'demo_form_validate'; break; } } function demo_form_submit($form, &$form_state) { //массив переданных значений содержится в $form_state['values'] //тут можно что то сделать с полученными данными - к примеру сохранить их в базу, db_query(...); //отправить email, и т.д. и т.п... в общем любые скрытые от пользователя действия drupal_mail($module, $key, $mail_addr, $lang, $params); //А в конце можно перевести пользователя на какую то специальную страницу с //сообщением об успешном сохранении данных (приеме заявки и т.п.) drupal_goto('node/100'); } function demo_form_validate($form, &$form_state) { //к примеру, проверка, что поле пустое и вывод сообщения об ошибке, //хотя именно для этого случая лучше использовать //свойство поля - #required, установив его как true, при объявлении формы. if (empty($form_state['values']['field1'])) { form_set_error('field1', 'А поле то надо заполнить!'); } } |