Form API Drupal 7 создание форм на Drupal
В прошлых уроках мы познакомились с хуками hook_block_info(), hook_block_view(), hook_menu(), hook_permission() и теперь можем создавать программно сколько угодно страниц и блоков. А в этом уроке мы ознакомимся с Form API Drupal 7 для создания форм. Мы будем создавать форму для администрирования функций модуля и постараемся использовать как можно больше уже известных нам хуков, чтобы закрепить умения.
Для начала мы выведем 3 блока, думаю для вас это не составит труда.
function sitemade_block_info(){
$blocks = array(); //инициализируем пустой массив
$blocks[1]['info'] = 'Список пользователей'; //заголовок блока для админки
$blocks[2]['info'] = 'Список нод';
$blocks[3]['info'] = 'Список терминов';
return $blocks; //возвращаем список блоков
}
function sitemade_block_view($delta = ''){
$block = array(); //инициализируем пустой массив блока
switch ($delta){
case 1: //такая же delta как мы возвращали в hook_block_info()
$block['subject'] = 'Пользователи'; //выводим заголовок блока
$block['content'] = ''; //инициализируем строковую переменную
$query = db_select('users', 'u') //запрос выборки пользователей
->fields('u', array('uid', 'name')) //выбор полей
->orderBy('u.uid', 'DESC') //сортируем по убыванию
->range(0, 5) //выбор пяти пользователей
->execute(); //запрос к БД
$users = $query->fetchAll(PDO::FETCH_ASSOC); //обрабатывает запрос в виде массива
foreach($users as $user){
$block['content'] .='<div><a href="' . base_path() . 'user/' . $user['uid'] . '">' . $user['name'] . '</a></div>';
// base_path() - функция возвращает путь к корню сайта
}
break;
case 2:
$block['subject'] = 'Ноды'; //выводим заголовок блока
$block['content'] = '';
$query = db_select('node', 'n')
->fields('n', array('nid', 'title'))
->orderBy('n.nid', 'DESC')
->range(0, 10)
->execute();
$nodes = $query->fetchAll(PDO::FETCH_ASSOC);
foreach($nodes as $node){
$block['content'] .='<div><a href="' . base_path() . 'node/' . $node['nid'] . '">' . $node['title'] . '</a></div>';
}
break;
case 3:
$block['subject'] = 'Термины'; //выводим заголовок блока
$block['content'] = '';
$query = db_select('taxonomy_term_data', 't')
->fields('t', array('tid', 'name'))
->orderBy('t.tid', 'DESC')
->range(0, 10)
->execute();
$terms = $query->fetchAll(PDO::FETCH_ASSOC);
foreach($terms as $term){
$block['content'] .='<div><a href="' . base_path() . 'taxonomy/term/' . $term['tid'] . '">' . $term['name'] . '</a></div>';
}
break;
}
return $block;
}
Очищаем кеш, чтобы наши новые блоки появились в админке. Выводим эти блоки в левый сайдбар:

Теперь сделаем страницу в админке, куда потом поместим форму для администрирования этих трех блоков:
function sitemade_permission(){
return array(
'admin content blocks' => array(
'title' => t('Admin content blocks'),
'description' => t('Nodes, Users, Terms'),
),
);
}
function sitemade_menu(){
$items = array(); // инициализируем массив наших пунктов меню
$items['admin/config/content/content_blocks'] = array(
'title' => 'Блоки пользователей, нод, терминов',
'description' => 'Администрирование блоков',
'page callback' => '_sitemade_content_blocks',
'access arguments' => array('admin content blocks'),
);
return $items; //возвращаем список страниц
}
function _sitemade_content_blocks(){
$content = 'Lorem ipsum!';
return $content;
}
Страницу создали, должна появиться такая вот заглушка по адресу admin/config/content/content_blocks:

И еще давайте выставим разрешения для администратора на просмотр этой страницы (для этого мы добавляли hook_permission()).

Теперь будем менять код наших хуков. Для начала создадим форму администрирования. Что мы будем администрировать в этих трех блоках? Я предлагаю заголовок блока и количество отображаемых сущностей (нод, пользователей, терминов).
Во-первых поменяется свойство хука hook_menu 'page callback'.
function sitemade_menu(){
$items = array();
$items['admin/config/content/content_blocks'] = array(
'title' => 'Блоки пользователей, нод, терминов',
'description' => 'Администрирование блоков',
'page callback' => 'drupal_get_form',
'page arguments' => array('_sitemade_content_blocks'),
'access arguments' => array('admin content blocks'),
);
return $items;
}
Ниже приведу описание функции drupal_get_form():
drupal_get_form($form_id)
Обертка для drupal_build_form() для использования когда $form_state не нужен.
Параметры drupal_get_form()
$form_id уникальный идентификатор для обрабатываем формы. Если функция с этим идентификатором существует, то вызывается контструктор массива форм. Модули нуждаются в похожем $form_id могут реализовываться в hook_forms(), который составляет список $form_id значений в нужную функцию конструктора.
Любые другие дополнительные аргументы переданные функцией будет вызваны drupal_get_form, подключаясь к уникальной функции конструктора форм. Например форма node_edit (редактирования ноды) требует чтобы объект ноды был передан когда форма вызывается. Это возможно через реализацию хука hook_form_alter() и hook_FORM_ID_alter() как массив $form_state['build_info']['args'].
Возвращаемое значение drupal_get_form()
Массив формы
Итак, теперь нам нужно переписать функцию _sitemade_content_block(), чтобы она возвращала массив формы.
function _sitemade_content_blocks(){
$form = array(); //инициализация массива форм
$form['nodes-title'] = array(
'#type' => 'textfield',
'#title' => t('Заголовок блока нод'),
'#default_value' => variable_get('node_block', ''),
'#size' => 60,
'#maxlength' => 64,
'#description' => t('Заголовок блока для Нод'),
);
$form['node-selected'] = array(
'#type' => 'select',
'#title' => t('Нод в блоке'),
'#options' => array(
1 => t('1'),
2 => t('2'),
3 => t('3'),
4 => t('4'),
5 => t('5'),
6 => t('6'),
7 => t('7'),
8 => t('8'),
9 => t('9'),
10 => t('10'),
),
'#default_value' => variable_get('node_block_range', 5),
'#description' => t('Количество нод выводимых в блоке'),
);
$form['users-title'] = array(
'#type' => 'textfield',
'#title' => t('Заголовок блока пользователей'),
'#default_value' => variable_get('user_block', ''),
'#size' => 60,
'#maxlength' => 64,
'#description' => t('Заголовок блока для Пользователей'),
);
$form['user-selected'] = array(
'#type' => 'select',
'#title' => t('Пользователей в блоке'),
'#options' => array(
1 => t('1'),
2 => t('2'),
3 => t('3'),
4 => t('4'),
5 => t('5'),
6 => t('6'),
7 => t('7'),
8 => t('8'),
9 => t('9'),
10 => t('10'),
),
'#default_value' => variable_get('user_block_range', 5),
'#description' => t('Количество пользователей выводимых в блоке'),
);
$form['terms-title'] = array(
'#type' => 'textfield',
'#title' => t('Заголовок блока терминов'),
'#default_value' => variable_get('user_block', ''),
'#size' => 60,
'#maxlength' => 64,
'#description' => t('Заголовок блока для терминов'),
);
$form['term-selected'] = array(
'#type' => 'select',
'#title' => t('Терминов в блоке'),
'#options' => array(
1 => t('1'),
2 => t('2'),
3 => t('3'),
4 => t('4'),
5 => t('5'),
6 => t('6'),
7 => t('7'),
8 => t('8'),
9 => t('9'),
10 => t('10'),
),
'#default_value' => variable_get('term_block_range', 5),
'#description' => t('Количество терминов выводимых в блоке'),
);
$form['actions'] = array('#type' => 'actions'); //добавляем кнопку сохранения
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
return $form;
}
'#type' - тип элемента.
'#title' - заголовок.
'#description' - описание.
'#options' - варианты выпадающего списка.
'#default_value' — значение по умолчанию, в данном случае мы подгружаем.
В результате форма администрирования должна стать такой:

Мы вывели форму, теперь нужно сделать обработку формы. Для обработки мы будем использовать хуки hook_formID_validate(), hook_formID_submit(), соответственно для проверки и обработки формы.
Генерация форм
Функции доступные для обработки и показа HTML-кода форм в Друпале.
Друпал использует эти функции для обеспечения совместимости обработки и показа форм, для упрощения кода и сокращения количества HTML-кода, который должен быть точно сгенерирован модулями. Главная функция среди используемых для этого в Друпале drupal_get_form(), которая используется для генерации HTML-кода формы. Форма может быть построена программно без участия пользователя с использованием функции drupal_form_submit().
drupal_get_form() принимает, обрабатывает и выводит сгенерированный HTML-код формы для модулей автоматически. Ниже пример как использовать drupal_get_form() и остальные функции для генерации форм.
<?php
$form = drupal_get_form('my_module_example_form');
...
function my_module_example_form($form, &$form_state) {
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);
return $form;
}
function my_module_example_form_validate($form, &$form_state) {
// Проверка корректности заполнения.
}
function my_module_example_form_submit($form, &$form_state) {
// Обработка запроса формы.
}
?>
Или с некоторым числом дополнительных аргументов:
<?php
$extra = "extra";
$form = drupal_get_form('my_module_example_form', $extra);
...
function my_module_example_form($form, &$form_state, $extra) {
$form['submit'] = array(
'#type' => 'submit',
'#value' => $extra,
);
return $form;
}
?>
Теперь давайте напишем обработку нашей формы, чтобы значения передаваемые с формы сохранялись в переменных друпала. Установим модуль Devel, который позволит использовать функцию dsm(), распечатывающую любые массивы и объекты. После этого добавим в модуль еще один хук:
function sitemade_content_blocks_submit($form, &$form_values){
dsm($form_values);
}
Это позволит вывести на экран значения передаваемые с формы:

И теперь можно легко вставить значения в переменные:
function sitemade_content_blocks_submit($form, &$form_values){
//dsm($form_values);
variable_set('node_block', $form_values['values']['nodes-title']);
variable_set('user_block', $form_values['values']['users-title']);
variable_set('term_block', $form_values['values']['terms-title']);
variable_set('node_block_range', $form_values['values']['node-selected']);
variable_set('user_block_range', $form_values['values']['user-selected']);
variable_set('term_block_range', $form_values['values']['term-selected']);
}
Форма готова, после отправки данных формы значения сохраняются в переменные с помощью variable_set(), а потом заполняются дефолтные значения полей с помощью variable_get.

Осталось еще изменить хук hook_block_view(), чтобы заголовки блоков и количество ссылок на сущности в них тоже считывались с помощью variable_get().
function sitemade_block_view($delta = ''){
$block = array(); //инициализируем пустой массив блока
switch ($delta){
case 1: //такая же delta как мы возвращали в hook_block_info()
$block['subject'] = variable_get('user_block', 'Пользователи'); //выводим заголовок блока
$block['content'] = ''; //инициализируем строковую переменную
$query = db_select('users', 'u') //запрос выборки пользователей
->fields('u', array('uid', 'name')) //выбор полей
->orderBy('u.uid', 'DESC') //сортируем по убыванию
->range(0, variable_get('user_block_range', 5)) //выбор пяти пользователей
->execute(); //запрос к БД
$users = $query->fetchAll(PDO::FETCH_ASSOC); //обрабатывает запрос в виде массива
foreach($users as $user){
$block['content'] .='<div><a href="' . base_path() . 'user/' . $user['uid'] . '">' . $user['name'] . '</a></div>';
// base_path() - функция возвращает путь к корню сайта
}
break;
case 2:
$block['subject'] = variable_get('node_block', 'Ноды'); //выводим заголовок блока
$block['content'] = '';
$query = db_select('node', 'n')
->fields('n', array('nid', 'title'))
->orderBy('n.nid', 'DESC')
->range(0, variable_get('node_block_range', 5))
->execute();
$nodes = $query->fetchAll(PDO::FETCH_ASSOC);
foreach($nodes as $node){
$block['content'] .='<div><a href="' . base_path() . 'node/' . $node['nid'] . '">' . $node['title'] . '</a></div>';
}
break;
case 3:
$block['subject'] = variable_get('term_block', 'Термины'); //выводим заголовок блока
$block['content'] = '';
$query = db_select('taxonomy_term_data', 't')
->fields('t', array('tid', 'name'))
->orderBy('t.tid', 'DESC')
->range(0, variable_get('term_block_range', 10))
->execute();
$terms = $query->fetchAll(PDO::FETCH_ASSOC);
foreach($terms as $term){
$block['content'] .='<div><a href="' . base_path() . 'taxonomy/term/' . $term['tid'] . '">' . $term['name'] . '</a></div>';
}
break;
}
return $block;
}
И теперь можно посмотреть результат на главной странице. И не забываем "Уходя - почисти кэш"!
