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; }
И теперь можно посмотреть результат на главной странице. И не забываем "Уходя - почисти кэш"!