Pull to refresh

Свои таблицы в БД на Drupal и их интеграция с views

Привет, хабр!
В Друпале как правило все данные хранятся в нодах, термах и сущностях другого типа (например commerce product). Да, есть ещё переменные, в которых хранятся настройки.
В нодах хранить данные удобно: есть куча модулей, хуки, настройки, права и т.п. И есть очень большой соблазн любые данные складывать в ноды/термы. Проблема лишь в том, что для каждого поля в ноде создаётся аж 2 таблицы (field_data_field_*, field_revision_field_*)! И при большом объёме данных удар по производительности очевиден.

Выход есть: в Drupal CMS есть очень удобное и простое API для создания своих таблиц, а модуль Views позаботился о том, чтобы этими данными можно было очень легко играться.

Под катом — руководство, как сделать свою таблицу на Друпал и интегрировать её с Views.
Чтобы интереснее было читать — создадим с нуля тестовый «портал» для скачивания торрентов.

Создание своей таблицы


Итак, ставим чистый Drupal 7.23, ставим на него модули Ctools, Views.
Создаём ноду типа Film с полями: field_film_image (постер), field_film_description (описание), создаём пару фильмов для теста.
Торренты будем хранить в кастомной таблице, ссылаясь на нужную ноду фильма.

Создаём тестовый модуль (назову его torrents).
В torrents.install прописываем hook_schema, где описываем нашу таблицу:
torrents.install
/*
 * hook_schema implementation
 */
function torrents_schema() {
  $schema['torrents'] = array(
    'fields' => array(
      // id торрента
      'id' => array(
        'description' => t('Torrent identifier'),
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      // название торрента
      'title' => array(
        'description' => t('Torrent title'),
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
      ),
      // nid фильма, к которому привязан торрент
      'nid' => array(
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => FALSE,
        'default' => 0,
        'description' => t('Film nid'),
      ),
      // ссылка на торрент
      'link' => array(
        'description' => t('Torrent link to download'),
        'type' => 'varchar',
        'length' => 255,
        'not null' => FALSE,
        'default' => '',
      ),
      // когда торрент добавлен
      'created' => array(
        'description' => t('Torrent added'),
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
    ),
    'primary key' => array('id'),
  );
   
  return $schema;
}


После включения модуля — таблица создаётся.
После отключения модуля и удаления — таблица удаляется.

Дружим нашу таблицу с views


В модуле torrents.module указываем, какой views api мы используем:
/**
 * Implements hook_views_api().
 */
function torrents_views_api() {
  return array(
    'api' => 3,
    'path' => drupal_get_path('module', 'torrents'),
  );
}


Создаём в папке с модулем файл torrents.views.inc, который собственно и содержит информацию о том, как вьюхам понимать данные в нашей таблице:
torrents.views.inc
/**
 * Implements hook_views_data()
 */
function torrents_views_data() {
  // объявляем новый тип вьюх - торренты
  $data['torrents']['table']['group'] = t('Torrents');
  $data['torrents']['table']['base'] = array(
    'field' => 'id',
    'title' => t('Torrents'),
    'help' => t('Torrents table contains torrents info and can be related to nodes'),
  );
 
  // мы ссылаемся на ноды, поэтому сообщаем для отношений
  // что нам надо прилепить в случае их использования
  $data['torrents']['table']['join'] = array(
    'node' => array(
      'left_field' => 'nid',
      'field' => 'nid',
    ),
  );
  $data['torrents']['nid'] = array(
    'title' => t('Film nid'),
    'relationship' => array(
      'base' => 'node',
      'base field' => 'nid',
      'handler' => 'views_handler_relationship',
      'label' => t('Related film for torrent'),
      'title' => t('Film nid'),
    ),
  );
  
  // далее мы для каждого поля определяем, какой хендлер в каких случаях использовать во вьюхах
  $data['torrents']['id'] = array(
    'title' => t('Torrent ID'),
    'field' => array(
      'handler' => 'views_handler_field',
      'click sortable' => TRUE,
    ),
    'sort' => array(
      'handler' => 'views_handler_sort',
    ),
    'filter' => array(
      'handler' => 'views_handler_filter_numeric',
    ),
    'argument' => array(
      'handler' => 'views_handler_argument_numeric',
    ),
  );

  $data['torrents']['created'] = array(
    'title' => t('Created timestamp'),
    'field' => array(
      'handler' => 'views_handler_field_date',
      'click sortable' => TRUE,
    ),
    'sort' => array(
      'handler' => 'views_handler_sort',
    ),
    'filter' => array(
      'handler' => 'views_handler_filter_date',
    ),
    'argument' => array(
      'handler' => 'views_handler_argument_date',
    ),
  );
  
  $data['torrents']['title'] = array(
    'title' => t('Title'),
    'help' => t('Just a title'),
    'field' => array(
      'handler' => 'views_handler_field',
      'click sortable' => TRUE,
    ),
    'sort' => array(
      'handler' => 'views_handler_sort',
    ),
    'filter' => array(
      'handler' => 'views_handler_filter_string',
    ),
    'argument' => array(
      'handler' => 'views_handler_argument_string',
    ),
  );
  
  $data['torrents']['link'] = array(
    'title' => t('Download link'),
    'help' => t('Download link'),
    'field' => array(
      'handler' => 'views_handler_field',
      'click sortable' => TRUE,
    ),
    'sort' => array(
      'handler' => 'views_handler_sort',
    ),
    'filter' => array(
      'handler' => 'views_handler_filter_string',
    ),
    'argument' => array(
      'handler' => 'views_handler_argument_string',
    ),
  );
  return $data;
}



Дописываем в torrents.module плюшку в виде блока с формой, чтобы добавлять торренты в таблицу.
Привожу код всего модуля:
torrents.module
/*
 * Form to submit torrents
 */
function torrents_add_form($form, &$form_state) {
  $form['title'] = array(
    '#type' => 'textfield',
    '#attributes' => array('placeholder' => 'Название'),
    '#required' => TRUE,
  );
  $form['link'] = array(
    '#type' => 'textfield',
    '#attributes' => array('placeholder' => 'Ссылка на торрент'),
    '#required' => TRUE,
  );
  
  $films = db_select('node', 'n')
    ->fields('n', array('nid', 'title'))
    ->condition('n.type', 'film')
    ->execute()
    ->fetchAllAssoc('nid');
  
  $options = array();
  foreach ($films as $value) {
    $options[$value->nid] = $value->title;
  }
  
  $form['film'] = array(
    '#type' => 'select',
    '#attributes' => array('placeholder' => 'Фильм'),
    '#options' => $options,
    '#required' => TRUE,
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Добавить торрент',
  );
  return $form;
}

/*
 * Submit torrents form callback
 */
function torrents_add_form_submit($form, &$form_state) {
  $id = db_insert('torrents')
    ->fields(array(
      'nid' => $form_state['values']['film'],
      'title' => filter_xss($form_state['values']['title']),
      'link' => filter_xss($form_state['values']['link']),
      'created' => time(),
    ))->execute();
}


/*
 * Implements hook_block_info()
 */
function torrents_block_info() {
  $blocks['add_torrent'] = array(
    'info' => t('Add torrent'), 
    'cache' => DRUPAL_NO_CACHE,
  );
  return $blocks;
}

/*
 * Implements hook_block_view()
 */
function torrents_block_view($delta = '') {
  $block = array();
  switch ($delta) {
    case 'add_torrent':
      $block['content'] = drupal_get_form('torrents_add_form');
      break;
    default:
      break;
  }
  return $block;
}

/**
 * Implements hook_views_api()
 */
function torrents_views_api() {
  return array(
    'api' => 3,
    'path' => drupal_get_path('module', 'torrents'),
  );
}



Созадём views



Далее просто включаем модуль и начинаем создавать вьюшку.
Если сделали всё правильно — у нас при создании вьюхи будет новый доступный тип для выбора: Torrents.
В полях можно будет добавить id торрента, название, ссылку.
В отношениях добавить nid фильма и потом использовать данные ноды.
Также есть фильтры по нашим полям, что конечно же удобно (хотя кое-чего не хватает).

Скриншоты, как это заработало
image

Вот они, наши поля:
image

Добавление отношения:
image



Посмотреть демо и добавить торрентов можно здесь.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.