Ромка!eu

  • Отдых
  • Работа
Главная — Блоги — Ромка's blog

Темизация Drupal. Часть 3. Основы Drupal Forms API и темизация форм

  • Просмотреть
  • Голоса

Ромка — Вс, 01/03/2010 - 22:58

441
point

Прежде чем говорить об изменении внешнего вида форм, ознакомимся с основами Drupal Forms API — программного интерфейса, используемого для генерации форм. Применение Forms API несколько сложнее создания HTML-форм вручную, так как требует изучения логики его работы, однако его использование обязательно, поскольку Forms API решает ряд важных задач:

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

Каждая форма в Drupal представляет собой функцию, возвращающую ассоциативный массив. Этот массив должен содержать информацию обо всех элементах формы, функциях проверки (валидаторы, validators) и обработки (сабмиттеры, submitters) введенных данных. Данная функция должна быть расположена в файле модуля, о разработке модуля говорилось в предыдущей статье.

На заметку: готовые решения

  • Темы оформления, позволяющие менять цветовую схему через интерфейс администратора: Pixture Reloaded, Dropshadow, Wabi, Garland (стандартная тема Drupal).
  • Темы оформления, обладающие множеством настроек и регионов: Deco, Acquia Marina.

Рассмотрим простой пример.

<?php
function test_form($form_state) {
  
$form["example_text_field"] = array(
    
'#type' => 'textfield',
    
'#title' => 'Example text field',
  );
  
$options = array(
    
0 => 'zero',
    
1 => 'one',
    
2 => 'two',
  );
  
$form["example_select"] = array(
    
'#type' => 'select',
    
'#title' => 'Example select list',
    
'#options' => $options,
    
'#description' => t('You can select only value "one" in this
      form'
),
  );
  
$form["submit"] = array(
    
'#type' => 'submit',
    
'#value' => t('Submit'),
  );
  return 
$form;
}
?>

Приведенная выше функция генерирует форму, состоящую из текстового поля, выпадающего списка с тремя элементами и кнопкой для отправки данных. Имя этой функции — ее уникальный идентификатор ($form_id), который будет использоваться для отображения и изменения данной формы сторонними модулями. Чтобы вывести форму на экран, нужно через hook_menu создать страницу, где будет вызвана функция drupal_get_form, принимающая в качестве параметра $form_id формы, которая должна быть отображена на экране:
<?php
function имя_модуля_menu() {
  
$items = array();
  
$items['test-form'] = array(
    
'title' => 'Test form',
    
'page callback' => 'test_form_page',
    
'access arguments' => array('access content'),
    
'type' => MENU_NORMAL_ITEM,
  );
  return 
$items;
}
function 
test_form_page() {
  return 
drupal_get_form('test_form');
}
?>

В массиве, возвращаемом функцией test_form($form_state), не определены процедуры проверки значений и заполнения полей (структур), поэтому ядро Drupal после нажатия на форме кнопки Submit попробует найти и выполнить функции form_id_validate и form_id_submit. В нашем случае, как легко догадаться, это будут функции с именами test_form_validate и test_form_submit:
<?php
function test_form_validate($form, &$form_state) {
  if(
$form_state['values']['example_select'] != 1) {
    
form_set_error('example_select', t('You must select value
      "one" in select list :)'
));
  }
}
function 
test_form_submit($form, &$form_state) {
  
drupal_set_message('Form sumitted! Values:');
  
drupal_set_message("textbox: " .
    
$form_state['values']['example_text']);
  
drupal_set_message("selectlist: " .
    
$form_state['values']['example_select']); 
}
?>

Функция-валидатор проверяет выбранное в выпадающем списке значение и, если оно не one, посылает сообщение об ошибке с указанием, какой элемент формы вызвал ошибку. Функция-сабмиттер выводит на экран введенные пользователем значения. В реальном случае эта функция должна будет сохранить данные в базе данных.

При желании программист может в массиве $form функции test_form задать свойство #submit, содержащее массив обработчиков значений и свойство #validate с массивом валидаторов (см. листинг 4). Оранжевыми комментариями выделены строки, добавленные к ранее описанным функциям.

Листинг 4

<?php
function test_form($form_state) {
  
$form["example_text_field"] = array(
    
'#type' => 'textfield',
    
'#title' => 'Example text field',
    
'#description' => 'Text must contain more then
      3 symbols'
,
  );
  
$options = array(
    
0 => 'zero',
    
1 => 'one',
    
2 => 'two',
  );
  
$form["example_select"] = array(
    
'#type' => 'select',
    
'#title' => 'Example select list',
    
'#options' => $options,
    
'#description' => t('You can select only value "one"
      in this form'
),
   );
  
$form["submit"] = array(
    
'#type' => 'submit',
    
'#value' => t('Submit'),
  );
//Добавлено
  
$form["#validate"] = array('test_validate_first',
    
'test_validate_second');
  
$form["#submit"] = array('test_submit_first',
    
'test_submit_second');
//Конец добавления
  
return $form;
}
?>

Код модуля также дополнится функциями из листинга 5.

Листинг 5

<?php
function test_validate_first($form, &$form_state) {
  if(
mb_strlen($form_state['values']['example_text_field']) < 3) {
    
form_set_error('example_text_field', t('Text must contain more then 3 symbols'));
  }
}
function 
test_validate_second($form, &$form_state) {
  if(
$form_state['values']['example_select'] != 1) {
    
form_set_error('example_select', t('You must select value "one" in select list :)'));
  }
}
function 
test_submit_first($form, &$form_state) {
  
drupal_set_message('First submitter');
  
drupal_set_message("textbox: " . $form_state['values']['example_text']);
}
function 
test_submit_second($form, &$form_state) {
  
drupal_set_message('Second submitter');
  
drupal_set_message("selectlist: " . $form_state['values']['example_select']); 
}
?>

Здесь добавлен валидатор, который проверяет текст, введенный в текстовое поле; если его длина оказывается меньше трех символов, то генерируется сообщение об ошибке.

При создании форм всегда рекомендуется использовать не стандартные валидаторы и сабмиттеры, а объявлять их явно, так как в этом случае сторонние программисты смогут дополнить массивы #submit и #validate своими функциями. Если используются стандартные валидаторы и сабмиттеры, то сторонние программисты смогут только заменить существующие функции своими, а это не всегда удобно.

Теперь вернемся к основной теме статьи — темизации Drupal. Функция drupal_get_form, получив на вход $form_id, идентификатор формы, которую нужно вывести на экран, вызывает функцию form_builder, проверяющую права доступа текущего пользователя к каждому из полей формы, и при наличии этих прав выводит стандартный HTML-код для каждого элемента формы. Каждый созданный элемент формы имеет уникальный атрибут id. Самый простой способ переопределения внешнего вида элементов формы — создание CSS-файла с описанием стилей нужных элементов формы. Если этого недостаточно, элементам формы можно добавить параметры #prefix и #suffix, которые будут содержать HTML-код, выводимый до и после созданного элемента. Если и этого мало, можно определить параметр #theme, который должен содержать используемое имя функции темизации.

Персональные функции темизации можно задать для всей формы целиком или для каждого ее элемента. По умолчанию Drupal для темизации формы пробует найти функцию theme_form_id, поэтому использование параметра #theme не обязательно.

Все функции, определенные параметром #theme, должны быть также объявлены через hook_theme (описание этого хука было дано в предыдущей статье).

Давайте изменим внешний вид созданного текстового поля. Для этого сначала создадим реализацию хука hook_theme:

<?php
function название_модуля_theme() {
  return array(
    
'example_text_field_theme_function' => array(
      
'arguments' => array('form' => NULL),
    ),
  );
}
?>

Затем модифицируем массив $form["example_text_field"], который создается в функции test_form, добавив в него параметр #theme:
<?php
$form
["example_text_field"] = array(
  
'#type' => 'textfield',
  
'#title' => 'Example text field',
  
'#description' => 'Text must contain more then 3 symbols',
  
'#theme' => 'example_text_field_theme_function',
);
?>

Теперь мы можем объявить функцию theme_example_text_field_theme_function и задать в ней любой HTML-код для отображения выбранного элемента:
<?php
function theme_example_text_field_theme_function($element) {
  
$class = "";
  if(isset(
$element["#needs_validation"])) {
    
$class = " error";
  }
  
$output = '<div id="' . $element["#id"] . '"
    class="form-item"><input id="edit-example-text-field"
     class="form-text' 
. $class . '" name="' . $element["#name"]
     . 
'"></div>';
  return 
$output;
}
?>

Кроме того, эту функцию можно переопределить, не изменяя кода модуля. Для этого в файле template.php, который находится в папке с текущей темой оформления, нужно создать копию этой функции, заменив в ней префикс theme на имя текущей темы.

Если в реализации hook_theme использовать параметр template, например, так:

<?php
function название_модуля_theme() {
  return array(
    
'example_text_field_theme_function' => array(
      
'arguments' => array('form' => NULL),
      
'template' => 'example-text-field',
    ),
  );
}
?>

то HTML-код, ответственный за отображение элемента Web-страницы в браузере, можно будет задавать не в исходном тексте функции темизации, а в отдельном файле-шаблоне с соответствующим именем; в нашем примере это example-text-field.tpl.php. Такой подход удобен, если с сайтом должны работать дизайнеры, не имеющие опыта Web-программирования.

Если же возникла необходимость изменить внешний вид всей формы, а не только отдельных ее элементов, нужно проделать то же самое: указать значение параметра #theme формы, объявить в hook_theme функцию темизации и, наконец, реализовать ее. Давайте внесем необходимые изменения в наш код. Функция hook_theme будет выглядеть следующим образом:

<?php
function название_модуля_theme() {
  return array(
    
'test_form_theme_function' => array(
      
'arguments' => array('form' => NULL),
    ),
    
'example_text_field_theme_function' => array(
      
'arguments' => array('form' => NULL),
    ),
  );
}
?>

Исходный текст обновленной функции test_form приводится в листинге 6.

Листинг 6

<?php
function test_form($form_state) {
  
$form['#theme'] = 'test_form_theme_function';
  
$form["example_text_field"] = array(
    
'#type' => 'textfield',
    
'#title' => 'Example text field',
    
'#description' => 'Text must contain more then
      3 symbols'
,
    
'#theme' => 'example_text_field_theme_function',//*/
  
);
  
$options = array(
    
0 => 'zero',
    
1 => 'one',
    
2 => 'two',
  );
  
$form["example_select"] = array(
    
'#type' => 'select',
    
'#title' => 'Example select list',
    
'#options' => $options,
    
'#description' => t('You can select only value "one"
      in this form'
),
  );
  
$form["submit"] = array(
    
'#type' => 'submit',
    
'#value' => t('Submit'),
  );
  
$form["#validate"] = array('test_validate_first',
    
'test_validate_second');
  
$form["#submit"] = array('test_submit_first',
    
'test_submit_second');
  return 
$form;
}
?>

Также нам потребуется и сама функция темизации формы. Определим ее:
<?php
function theme_test_form_theme_function($form) {
  
$output = "Some additional text";
  
// Выводим некоторые элменты отдельно с дополнительным
  // форматированием
  
$output .= '<div style="background-color: #ccc; padding:
    3px;">'
;
  
$output .= drupal_render($form['example_text_field']);
  
$output .= "</div>";
  
// Выводим остальные элементы, которые не были выведены
  // ранее
  
$output .= drupal_render($form);
  return 
$output;
}
?>

Как и с любой другой функцией темизации, ее содержимое можно вынести во внешний шаблон.

Ну а теперь осталось научиться модифицировать из внешнего модуля существующую форму. Для решения этой задачи нужно воспользоваться одним из двух хуков: или hook_form_alter, через который проходят массивы всех обрабатываемых форм и в котором каждый массив можно отредактировать, или hook_form_FORM_ID_alter, где FORM_ID должен быть заменен на идентификатор нужной формы. Через этот хук проходит только выбранная форма. На вход оба этих хука получают массив формы (в нашем примере это массив, который генерируется функцией test_form), и в этот массив могут быть добавлены или из него могут быть удалены любые параметры: #theme, #prefix, #suffix, #submit, #validate и другие.

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

<?php
function название_модуля_form_test_form_alter(&$form,
    &
$form_state) {
  
$form["example_text_field"]["#title"] = "New title";
  
$form["example_add_field"] = array(
    
'#type' => 'fieldset',
    
'#title' => 'new fieldset',
    
'#collapsible' => TRUE,
    
'#collapsed' => FALSE,
    
'#weight' => 0,
  );
  foreach (
$form as $name => $element) {
    if(
$element["#type"] == "select" || $element["#type"] ==
        
"textfield") {
      
$form["example_add_field"][$name] = $element;
      unset(
$form[$name]);
    }
  }
  
$form["submit"]["#weight"] = 5;
}
?>

Вот и все.

Ссылки на другие части этой статьи:

  • Часть 1. Введение
  • Часть 2. Анатомия темы оформления
  • Часть 3. Forms API и темизация
  • Часть 4. Темизация Views

Содержание всех статей: http://romka.eu/blog/my-drupal-articles

  • Drupal
  • статья
  • темизация
  • формы Forms API
  • Ромка's blog
  • Quote

Спасибо!

Anonymous (не проверено) → Сб, 03/27/2010 - 00:31

Спасибо!

  • ответить
  • quote
  • -17 points

Немного подробнее, плз

serge che (не проверено) → Вс, 08/15/2010 - 19:13

Как без form_set_error объявить форму непрошедшей валидацию?
Заранее спасибо за ответ :)

  • ответить
  • quote
  • -21 points

свои настройки в теме

joomler (не проверено) → Чт, 09/16/2010 - 21:48

Расскажите как создать свои кастомные настройки для темы оформления, чтобы в админке пользователь мог поменять ширину колонок, отображать или нет автора ноды, выбрать бэкграунд для сайта и т.п.
На русском статей я не нашел, на Д.орг есть немного инфы но недостаточно абсолютно http://drupal.org/node/177868
Темы от http://fusiondrupalthemes.com используют skinr и все эти настройки, темы для Джумлы от Рокетов и прочих используют это уже давно, а для Друпала все очень плохо...

  • ответить
  • quote
  • -1 points

Читайте о темизации друпала,

Anonymous (не проверено) → Пт, 10/08/2010 - 22:59

Читайте о темизации друпала, сложного там в азах ничего нет...

  • ответить
  • quote
  • -13 points

щас использую

joomler (не проверено) → Пт, 10/08/2010 - 23:40

щас использую http://drupal.org/project/style_settings для настроек, пришлось повозиться с мануалом чтобы все настроить.
меня не сложность беспокоит а то что вот вышла уже бета 1 для Д7 а шаблонов на него вообще нет от коммерческих производителей, очень уж медленно происходит становление отрасли шаблонов, качество их намного ниже чем жумловских а цены выше (да да знаю что до беты апи не устоялся и нельзя было делать шаблоны)

  • ответить
  • quote
  • -18 points

Не совсем то

Anonymous (не проверено) → Пт, 12/17/2010 - 02:04

не совсем то что искал...

http://yandex.ru/yandsearch?clid=48648&yasoft=barff&text=%D0%90%D0%94%D0%A0%D0%95%D0%A1+api+%D0%A1%D0%95%D0%A0%D0%92%D0%95%D0%A0%D0%90+%D0%94%D0%9B%D0%AF+%D0%94%D0%A0%D0%A3%D0%9F%D0%90%D0%9B&lr=10849

  • ответить
  • quote
  • -12 points

Странный какой то пример:

Михаил (не проверено) → Втр, 12/21/2010 - 16:31

Странный какой то пример: theme_test_form_theme_function - повторно пересоздавать вывод, когда он уже создан, чтобы сместить элемент вперед. Корректней наверное череp hook_form_alter '#weight' позадавать.

  • ответить
  • quote
  • 8 points

Извиняюсь, понял, что не

Михаил (не проверено) → Ср, 12/22/2010 - 15:49

Извиняюсь, понял, что не прав. Просто без точного понимания работы функции drupal_render не понятна тема, а в статье это не объясняется.
Например, первое что приходит в голову: $form['#theme'] переопределит стандартную функцию тем для формы theme_form, что на самом деле не так.

  • ответить
  • quote
  • -18 points

с чем?

Михаил (не проверено) → Вс, 12/26/2010 - 17:40

с чем?

  • ответить
  • quote
  • -27 points

Re: да и сейчас красивая

Бобров Вячеслав → Вс, 02/06/2011 - 00:37

да и сейчас красивая

  • ответить
  • quote
  • -24 points

Добрый день ! Есть такая

Anonymous (не проверено) → Чт, 02/24/2011 - 18:11

Добрый день !

Есть такая проблема.

Вывожу несколько одинаковых форм на странице.
Каждая форма генерируется одной и той же функцией test
То есть я для каждой формы вызываю drupal_get_form с уникальным id - test_1, test_2 etc
а затем переопределяю функцию создания формы в hook_forms
('callback' => 'test',)
В функции test я прописываю в форме
'#theme' => 'test'
и создаю соответственно функцию темы. theme_test

При выводе тема вызывается, но в нее передается пустая форма - то есть видимо оно пытается найти форму test , а у меня имеются формі test_1, test_2 и тд...

Каким образом можно еще темизировать одинаковые формы с различными ID одной функцией темы ?

Заранее спасибо !

  • ответить
  • quote
  • -22 points

Не везде понятно, где код

Сережа (не проверено) → Пнд, 04/04/2011 - 11:42

Не везде понятно, где код должен прописываться в некоторых листингах.

Поясните пожалуйста.

  • ответить
  • quote
  • -22 points

Куда вставлять хук?

Рашид (не проверено) → Втр, 11/01/2011 - 11:42

Подскажите пожалуйста, многоуважаемый гуру следующие вещи:
1) куда именон, в какой файл мне вставить hook_form_alter()
2) как мне узнать имя формы модуля Contact? (хочу изменить автозаполнение текстового поля в форме обратной связи модуля contact)

  • ответить
  • quote
  • -2 points

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
  • Доступны HTML теги: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Строки и параграфы переносятся автоматически.
  • Вы можете использовать тэг <code></code> для подсветки синтаксиса программного кода. The supported tag styles are: <foo>, [foo].
  • You may quote other posts using [quote] tags.

Подробнее о форматировании

CAPTCHA
Если вы человек, а не робот, то введите текст с картинки. Если вы робот, то велкам ту майкрософт.ком.

Обо мне

Всем привет!
Меня зовут
Роман Архаров, я профессиональный веб-разработчик, программирую на языках PHP, Python и Action-Script, в работе использую фреймворки Drupal и Django. В этом блоге я размещаю заметки и статьи, связанные с моей работой, отдыхом и другими интересными мне темами.

Похожие заметки

  • Несколько статей о Друпале
  • Темизация Drupal. Часть 2. Анатомия темы оформления Drupal
  • Темизация Drupal. Часть 1
  • Пример разработки плагина для модуля CCK
  • Темизация Drupal. Часть 4. Темизация Views

Популярные заметки

  • Пример разработки плагина для модуля CCK
  • AJAX. Обмен данными между клиентом и сервером, закачка на сервер файлов без перезагрузки страницы при помощи библиотеки jQuery.
  • Модуль Vote Up/Down для Drupal 6
  • Темизация Drupal. Часть 1
  • Темизация Drupal. Часть 2. Анатомия темы оформления Drupal
  • Авторизация на Drupal-сайте с помощью аккаунта ВКонтакте
  • Кнопки Home, End и Page Up, Page Down в Mac OS
  • Темизация Drupal. Часть 3. Основы Drupal Forms API и темизация форм
  • Вращение изображений при помощи Javascript
  • Разработка сайта на Drupal. Часть 4. Пример разработки корпоративного интранет-сайта на Drupal

Подписка


Последние комментарии

  • Oz → Швабрашвабр2 → слабовато для
  • loan → Вращение изображений при помощи Javascript → answer this topic
  • CopelandLacey33 → Доставка → reply this post
  • vitsss → Авторизация на Drupal-сайте с помощью аккаунта вКонтакте → hostinh nic.ru and vk api
  • dimasikov → Автоматическая "газетная" верстка (верстка в несколько колонок) → Я похожее делал для с этим
  • max2012 → Разработка сайта на Drupal. Часть 2. Архитектура Drupal. → Подвесные потолки Опосля
  • Антон → Темизация Drupal. Часть 4. Темизация Views → Отлично!
  • Itsmypersonal → Зима 2010. Поездка в Тайланд, Индонезию и Сингапур. Часть 2 — Пхукет → Пхукет - да!
  • Sheldon → Перетаскивание ячеек таблицы. Table drag and drop — плагин для jQuery → Здравствуйте! Подскажите
  • Sheldon → Home sheep home → Одна из тех игр в которые

Новые заметки

  • Проба пера в HTML5 + canvas. Эффект ластика
  • Шесть рукопожатий
  • Доклад на DrupalConfMoscow 2011
  • Статусы разных сущностей в Друпале 6
  • Футер, прибитый к низу страницы
  • Путешествие по Перу и Боливии. Часть 2
  • Путешествие по Перу и Боливии. Часть 1
  • Несколько панорам из путешествия по Перу и Боливии
  • Авторизация на Drupal-сайте с помощью аккаунта ВКонтакте
  • Home sheep home

Тэги

dckyiev09 Drupal jquery Боливия Отдых Перу Работа Штуки-дрюки зима 2010 модуль статья темизация
еще тэги

Вход для пользователей

Что такое OpenID?
  • Войти по OpenID
  • Скрыть вход по OpenID
  • Зарегистрироваться
  • Запросить новый пароль

Навигация

  • Exchange rate
  • Vote up/down
  • Переход по внешней ссылке
  • Последние сообщения
  • Фотогалереи

Курсы валют

  • 100 Казахских тенге — 20,3352 (+0.03)
  • 10 Украинских гривен — 37,6101 (+0.06)
  • 10 Китайских юаней — 47,9611 (+0.04)
  • 100 Японских иен — 39,6909 (-0.04)
  • 1 Доллар США — 30,2385 (+0.05)
  • 1 Евро — 39,7425 (-0.02)
  • 10000 Белорусских рублей — 35,9554 (-0.07)
  • 1 Турецкая лира — 17,1829 (-0.03)

10 случайных заметок

  • Перетаскивание строк таблицы. Table drag and drop — плагин для jQuery
  • Получение заголовков (HTTP-headers) страницы при помощи Java-script
  • mini.romka.eu — версия этого сайта для КПК
  • Модуль Vote Up/Down для Drupal 6
  • Путешествие по Перу и Боливии. Часть 1
  • С Новым Годом!
  • Рассуждение на тему «Сколько стоит сайт?»
  • Проба пера в HTML5 + canvas. Эффект ластика
  • Странное поведение Java-script в IE. Один и тот же скрипт в Firefox работает, а в IE – нет.
  • Drupal for Firebug

Случайные фото

Старая и новая наши машины — пыжик и сузуки джимни
Копенгаген, Кристиания, Граффити 6
Экзотическое меню в аэропорту :))
Тринидадские спортсменчики
Я и моя тень
Красная поляна
И у люююбви у нааашеей сееела...
Копенгаген, Кристиания, Граффити 7
Градиент
Пустыня
Замок Акерхус вечером
Радуга над футбольным полем в Лужниках
Я и кокос... Где то я это уже видел...
Бронзовое море
Еще одно фото резиденции короля
Копенгаген, Кристиания, Граффити 3
  • Отдых
  • Работа

При использовании материалов с сайта, пожалуйста, ставьте ссылку на источник. E-mail для связи: mne@romka.eu.