Закончил перевод очередной статьи из цикла "20 API за 20 дней". В ней речь идет, пожалуй, о самом обсуждаемом API Друпала - об API форм. В заметке коротко рассматриваются вопросы создания, валидации и сохранения формы, ее темизации и использования AHAH.
Оригинальная статья: The Forms API.
Автор: Кайл Каннингэм.
API форм
Об API форм Друпала сказано уже немало, однако для разработчиков, ранее работавших на других платформах, концепция может оказаться непростой. Любая статья о фреймворках была бы неполной без обсуждения способов их применения.
API форм Друпала обеспечивает разработчиков возможностью динамически создавать, изменять и валидировать формы на веб-сайтах. Вместо того, чтобы создавать разметку для каждого элемента формы, разработчики задают форму через массив, в котором содержатся инструкции для Друпала о том, как сгенерировать форму и показать ее пользователям. API форм также рассказывает Друпалу, как валидировать данные формы и что с этими полученными данными делать.
Настоящая мощь API форм заключается в том, что сторонние модули могут изменять любые формы в процессе их генерации. Разработчики могут создавать новые поля, добавлять дополнительные условия валидации и динамически обрабатывать сохранение данных формы. Такого рода расширяемость - уникальная черта Друпала - представляет собой весьма необычную модель разработки веб-приложений.
Зачем вообще API форм?
Формы - неотъемлемая часть Интернета, позволяющая веб-сайтам собирать пользовательские данные. Иметь в наличии платформу, позволяющую легко обрабатывать сохранение форм, - очень важно, особенно если учесть, какие решения были раньше.
На рассвете Интернета сохраняемые формы обычно обрабатывали через cgi-скрипты. Эти скрипты как правило использовали однопоточные дистрибы Perl и были ужасно медленными в сравнении с современными технологиями. С некоторыми из основных проблем разработчики, администраторы и операторы сайтов боролись с помощью обработки форм запутанными bash-скриптами, встречаясь при этом с проблемами потоков на сервере при валидации сохраненных данных форм для предотвращения их некорректного использования. Часто встречающимся способом положить веб-сайт было сохранение формы с большим количеством информации, чем предусматривалось обработчиком данных. Это приводило к проблемам нехватки памяти, блокировке потоков, ошибкам сегментации и многим другим гадостям.
И каждый фреймворк для разработки веб-приложений был вынужден разбираться с таким положением дел. Подход, выработанный в сообществе Друпала, в чем-то уникален, он подчеркнуто гибок на многих уровнях. Подход включает:
- автоматическую генерацию форм через основанные на массивах прототипы;
- возможность динамически модифицировать структуру формы в сторонних модулях;
- возможность валидировать данные формы при сохранении;
- возможность добавлять функции-обработчики сохраняемых данных;
- возможность модифицировать порядок сохранения формы;
- возможность динамически перенаправлять пользователя после сохранения формы на заданное содержимое.
Если задуматься, пройти все эти уровни обработки формы - серьезная задача для PHP-приложения. Друпал также обеспечивает возможности для кэширования форм, чтобы предотвратить необходимость их генерации с нуля при каждом запросе страницы. Это улучшает производительность, но может привести к некоторым серьезным последствиям для разработчика.
Простой пример
Создание формы в Друпале - относительно простой процесс. Каждая форма объявляется внутри PHP-функции как показано ниже:
function myform($form_state) {
$form['mytext'] = array(
'#type' => 'textfield',
'#title' => t('My Text'),
'#description' => t('Enter your text'),
'#required' => TRUE,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);
return $form;
}
Итак, как мы уже обсудили, каждая форма в Друпале - структурированный массив значений. Этот массив позволяет вам задавать тип используемого элемента формы (текстовое поле, селектбокс, радио-кнопки и т.д.), указывать, является ли данный элемент формы обязательным к заполнению, и другие полезные атрибуты. Для описания элементов формы существует множество атрибутов, их полный список можно найти на странице описания Forms API на сайте api.drupal.org.
Теперь чтобы сгенерировать и отобразить форму на веб-странице, все, что требуется сделать - это вывести ее через простую команду:
print drupal_get_form('myform');
Этот код возвращает простую форму с текстовым полем и кнопкой сохранения.
Валидация и обработка сохранения
Когда форма сгенерирована, Друпалу необходимо знать, что делать с информацией, приходящей через нее. Обработка сохранения формы состоит из двух шагов: валидации и сохранения.
Валидация - это шаг в процессе сохранения формы, на котором полученные данные проверяются на предмет корректности. Друпал автоматически проверяет, заполнены ли обязательные поля. В функции валидации разработчики могут разместить код, в котором будут проверять значения формы на соответствие требованиям их приложения. Например, если вы ожидаете в определенном поле число, на этом шаге вы проверяете, что введено именно число. В Друпале есть несколько специальных функций, позволяющих установить сообщение об ошибке и попросить пользователя ввести правильные значения.
Сохранение - это шаг в процессе сохранения формы, на котором мы манипулируем данными. Если форма не может пройти валидацию, данные никогда не достигнут стадии сохранения. Разработчики используют функции сохранения для записи данных, полученных через онлайн-форму, и для остальной необходимой обработки.
Как и все прочее в API форм, функции валидации и сохранения определяются динамически. Самый простой способ создать эти функции - дать им такое же имя, как у формы. Для формы из примера выше, функции myform_validate и myform_submit будут автоматически обрабатывать сохранения этой простой формы.
function myform_validate($form, &$form_state) {
// Проверяем, что все на месте
if (strlen($form_state['values']['mytext'])
form_set_error('mytext', t('The text you entered must be at least 80 characters long.'));
}
}
function myform_submit($form, &$form_state) {
drupal_set_message($form_state['values']['mytext']);
}
Функция form_set_error выставляет ошибку для заданного элемента формы. В данном случае мы проверяем, что наше текстовое поле mytext содержит текст из хотя бы 80 символов, а если это не так - выставляем ошибку формы. Ошибка отображается пользователю через статусное сообщение, кроме того, элемент формы будет подсвечен красным, чтобы пользователь знал, где именно произошла ошибка.
Функции myform_validate и myform_submit - это дефолтные функции обратного вызова для валидации и сохранения формы соответственно. Использующиеся по умолчанию функции, можно заменить, или же добавить дополнительные функции валидации и сохранения. В Друпале для этого есть два массива, входящих в описание формы:
// Добавляем функцию обратного вызова для валидации
$form['#validate'][] = 'my_new_validation_function';
// добавляем еще одну функцию обратного вызова - для сохранения
$form['#submit'][] = 'my_new_submission_function';
Эти функции будут вызываться в порядке размещения в массивах. Их использование даст вам возможность сделать поведение своих модулей более утонченным.
Темизация форм
Хотелось бы создавать не только функциональные, но и красивые формы! К счастью, Друпал обеспечивает методику, следуя которой вы сделаете формы сексапильными. Первое, что нам потребуется сделать - это рассказать слою темизации Друпала, что мы хотим кое-что темизировать. Это делается через hook_theme.
function mymodule_theme() {
return array(
'myform' => array(
'arguments' => array('element' => NULL),
),
);
}
Таким образом мы информируем слой темизации о том, что будем применять темизирующую функцию. Напомним, что Друпал автоматически генерирует название для этой функции. В нашем случае, поскольку мы сказали слою темизации, что темизируем форму myform, функция будет называться просто theme_myform. В темизирующей функции мы можем использовать drupal_render() для генерации HTML-кода элементов нашей формы.
function theme_myform(&$element) {
// Темизирующая форму функция всегда принимает первым аргументом
// элементы формы. Теперь мы можем добавлять свою разметку
// или еще как-то изменять отображаемую форму.
$output = '<h2>' . t('Our customisation to the theme') . '</h2>';
$output .= drupal_render($element['mytext']);
$output .= drupal_render($element['submit']);
//Эта строчка отрендерит все элементы формы, которые еще не были отрендерены.
//Полезно для скрытых полей, хорошо использовать, чтобы убедиться, что мы ничего не упустили
$output .= drupal_render($element);
return $output;
}
Единственное, что нам осталось, это модифицировать массив формы, чтобы указать в нем нашу новую темизирующую функцию.
$form['#theme'] = 'myform';
Эта техника может быть использована на любом уровне массива элементов формы. То есть, хотите ли вы изменить внешний вид всей формы или только текстового поля - Друпал делает эту задачу легко решаемой.
AJAX в формах
Теперь, когда мы охватили основы, можно добавить пикантности. Допустим, мы хотим сохранять форму через AJAX. Это лишь вопрос добавления небольшого кода к нашей форме. Прежде всего, у кнопки сохранения формы есть свойство #ahah (AHAH расшифровывается как Asynchronous HTML and HTTP - Асинхронный HTML и HTTP). Оно позволяет Друпалу узнать, что при нажатии кнопки должно произойти действие AJAX.
Вы наверное заметили, что один из элементов массива AHAH - это 'path'. Он содержит внутренний путь Друпала, к которому произойдет обращение при нажатии кнопки. Так что создадим его через hook_menu() Друпала.
function mymodule_menu() {
$items['ajaxsubmit'] = array(
'page callback' => 'ajaxsubmit',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
);
}
function myform_sweet($form_state) {
$form['mytext'] = array(
'#prefix' => '',
'#suffix' => '
',
'#type' => 'textfield',
'#title' => t('My Text'),
'#description' => t('Enter your text'),
'#required' => TRUE,
);
$form['submit'] = array(
'#type' => 'textfield',
'#value' => 'submit',
'#ahah' => array(
'path' => 'ajaxsubmit',
'wrapper' => 'wrapper'
'method' => 'replace',
'effect' => 'fade',
),
);
return $form;
}
function ajaxsubmit() {
// Здесь устанавливаем значение
drupal_set_message(t("Value set!"));
$messages = theme('status_messages');
return drupal_json('data' => $messages, 'status' => TRUE);
}
Вот, собственно, и все. Есть еще изюминки, которые мы не рассмотрели из соображений рациональности. Более подробно с AHAH в Друпале можете ознакомиться здесь.
Погодите, и еще
API форм - один из самых обсуждаемых разделов Друпала. Перечисление всего, что вы можете делать с его помощью, явно выходит за рамки статьи. Вот некоторые темы, которые вам, возможно, захочется изучить:
- Руководство для быстрого старта с API форм
- Описание API форм Друпала
- Определение собственных элементов формы
- Темизация форм
- Создание многостраничных форм с помощью Chaos Tools
- Загрузка файлов через формы
- Динамические AJAX-формы
Убедитесь, что прочли все наши статьи про API — в них мы исследуем основные инструменты расширения функций Друпала.
-----------------------------------
Итого на данный момент переведены все существующие заметки цикла. Авторы из компании Trellon уже две недели не выкладывают новых статей - то ли заняты, то ли сдулись. Но если статьи все же появятся - будут обязательно переведены.