Создание иерархических списков (Страна-Город-Университет)

Главные вкладки

Аватар пользователя Larus Larus 24 ноября 2008 в 11:38

В разрабатываемом проекте (под Drupal v.5) понадобилось создать много разных иерархических списков: пользователь выбирает значение первого уровня, далее ему показываются данные, относящиеся к выбранной категории, и т.д. для реализации выбора Страна-Город-Университет/Школа, Производитель-Марка-модель машины и т.п.

Есть замечательный модуль http://drupal.org/project/hierarchical_select (далее HS), который:
1. Сохраняет всю цепочку выбора пользователя
2. Позволяет конфигурировать до какого уровня пользователь должен/может выбирать данные, на каких уровнях пользователь может создавать свои данные/уровни.
3. Позволяет конфигурировать количество выбранных пользователем элементов
4. Предоставляет возможности конфигурации dropbox (участка, где выводится выбранная цепочка)

Кроме того, есть модуль http://drupal.org/project/content_taxonomy, который позволяет добавлять выбранные в hierarhical_select данные в поле CCK. Но. Для версии Друпал 5 на момент написания данного сообщения модуль находится в dev-версии, и не позволяет (как показали тесты в домашних условиях) сохранять несколько значений из HS для нода.

После изучения API Hierarchical Select сделала модуль с формой выбора университета (в моем случае) используя словарь Таксономии и сохранение и отображение всех выбранных пользователем элементов. Дальнейшие действия по удалению уже выбранного, отображению формы в виде вкладки/пункта меню, вывод "себе подобных" рассмотрю в отдельной записи, тут же хочу остановиться на создании формы с Hierarchical Select и получении значений из нее по Submit.

Итак, последовательность действий:

1. Скачать с http://drupal.org/project/hierarchical_select модуль.
2. Скачать и установить согласно инструкциям jQuery Update 2.x с http://drupal.org/project/jquery_update
3. Через admin/content/taxonomy создать новый Vocabulary, Заполнить обязательные к заполнению поля и пометить в пункте Hierarchy: как Single. Остальными настройками можно пренебречь, все равно далее данные будут выводиться через форму.

4. Создать форму (в комментариях к строкам я указываю, какие поля и для чего нужны)

<?php
function university_select_nameform() {
  $form['select_some_term'] = array(
    //указываем тип данного как hierarchical_select, а не как select
    '#type' => 'hierarchical_select',
    //заголовок для поля
    '#title' => t('Select your university, please, or create own'),
    //размер отображаемых в поле select строчек
    '#size' => 1,

    '#config' => array(
      'module' => 'hs_taxonomy', //обязательное поле.
      'params' => array(
        'vid' => 5, //ссылка на id созданного ранее Vocabulary
        'exclude_tid' => 0, //этого и следующего параметра нет в описании API, но без их указания не работает форма
        'root_term' => 0, // поэтому значения тут стоят 0. Если у кого-то есть идеи, что сюда подставить - отпишитесь в комментариях, пожалуйста
      ),
      'save_lineage'    => 1, //Сохранять или нет всю цепочку выбора в формате "страна-город-университет" или просто последнее выбранное значение
      'enforce_deepest' => 0, //Заставлять или нет выбирать самый глубокий (в приведенном примере: университет) пункт или принимать значение на любом уровне
      'entity_count'    => 0, //выводить или нет количество выбранных пунктов
      'resizable'       => 0, //разрешать или нет изменение размера списка (по вертикали)
      'level_labels' => array( //управление labels для списков
        'status' => 0, //разрешить отображение или нет
        'labels' => array( //сами названия для списков (приведено просто для примера, все равно в моем случае они не будут отображаться)
          0 => t('Main category'),
          1 => t('Subcategory'),
          2 => t('Third level category'),
        ),
      ),
      'dropbox' => array( //управление отдельным блоком, куда выводятся выбранные пункты
        'status'   => 1, //отображать или нет
        'title'    => t('All selections'), //заголовок
        'limit'    => 0, //количество выбранных пунктов (0-без ограничений)
        'reset_hs' => 1, //сбрасывать или нет выбранные пункты, после нажатия на кнопку "Add"
      ),
      'editability' => array( //управление редактированием списков иерархии
        'status'           => 1, //разрешить или нет редактировать
        'item_types'       => array(),
        'allowed_levels'   => array( //на каких уровнях разрешить создание новых пунктов: 0 - не разрешать, 1 - разрешить
          0 => 1,
          1 => 1,
          2 => 1,
        ),
        'allow_new_levels' => 1, //разрешить или нет создание новых уровней в иерархии
        'max_levels'       => 3, //максимальное количество уровней
      ),
      // These settings cannot be configured through the UI: they can only be
      // overridden through code.
      'animation_delay'    => 400, //задержка в перерисовке выпадающих списков
      'exclusive_lineages' => array(),
      'render_flat_select' => 0,
    ),
    '#default_value' => '0',
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit')
  );
  $form ['#tree'] = TRUE;
  return $form;
}
?>

Много времени ушло на выяснение, через какое поле в Submit формы получить выбранные пользователем значения.
Оказалось, что значения передаются массивом через значение select_some_term.

 $leaves = $form_values['select_some_term']

Что интересно, передаются все выбранные пункты цепочки, а совпадающие значения пропускаются.
Например, если выбрать Страна1-город1-Университет1 и Страна1-город1-Университет2, то передадутся значения Страна1, город1, университет1, университет2.

Поэтому в обработчике submit пробегаемся по списку полученных значений, находим самые нижние пункты (листья), сохраняем их отдельно и используем их в зависимости от наших интересов.

Как вариант, при включенном usernode, можно сохранить связь в таблице term_node между пользователем и полученным term, для дальнейших манипуляций по поиску "своих" единомышленников, удалению/редактированию выбранных ранее пунктов и т.д.

Wink

Комментарии

Аватар пользователя pachkow@drupal.org pachkow@drupal.org 3 декабря 2008 в 12:47

Спасибо за статью. Теперь данный подход использую в разных модулях, например, переписал для своих нужд модуль Profile (чтобы можно было выбрать район области и школу из списка).

Аватар пользователя qm69 qm69 30 декабря 2009 в 19:57

Извиняюсь за глупый вопрос, но c Drupal’ом я познакомился недавно и сейчас на стадии альфа обучения и не понимаю, куда нужно вставить код?
- усе модули распаковал согласно выше написанным инструкциям.
- создал словарь, наполнил его терминами с единичной иерархией.
- создал CCK материал «список чего-то там очень архи важного»
- в нем нужно добавить поле типа Taxonomy Field и выбрать 1 из 4 на выбор?
А куда тогда php код? Распечатать и в письме послать на хостинг?
Понимаю что я тут не один такой, так что этим вы поможете многим будущим повелителям ядра друпала.

Аватар пользователя qm69 qm69 30 декабря 2009 в 22:15

RxB wrote:
Будущим повелителям ядра друпала до этого топика ещё далеко

Путь в 1000 ле начинается с одного шага.
Но все равно спасибо тебе ХиЙ за то что хотя бы нашел время просмотреть мой комментарий.

Аватар пользователя Виктор Степаньков ака RxB Виктор Степаньк... 30 декабря 2009 в 22:22

Ну а какой ответ вы ожидали получить? У вас вопрос мало касается данного топика, в остальном:
- в нем нужно добавить поле типа Taxonomy Field и выбрать 1 из 4 на выбор?
Вам нужен список? Значит список и выбирать
-А куда тогда php код? Распечатать и в письме послать на хостинг?
Внимательный читать топик