Views API часть 1 (подключаем свою таблицу )

Аватар пользователя gumk gumk 9 июня 2010 в 0:05

Бывают случаи когда нужно подключить таблицу из своего модуля ко views, а документации по этому поводу на русском языке нет.
Так как сам достаточно долго с этим промучился напишу ликбез, основываясь на документации http://views.doc.logrus.com/main.html и своем опыте, поехали!

1) нужно создать в корне модуля файл имямодуля.views.inc
*Если этот файл лежит не в корне модуля, то необходимо поместить hook_views_api() в файл .module
и указать в параметре 'path' путь к файлу, если файл лежит в корне папки модуля параметр 'path' можно опустить.

<?phpfunction hook_views_api() {
   return array(
     
'api' => 2,
     
'path' => drupal_get_path('module''example') . '/includes/views'
   );
 }
?>

2) Описываем таблицу в новом файле, применяя hook_views_data()

Допустим у нас таблица содержит разные данные и имеет следующее строение:
/ CREATE TABLE example_table (
// nid INT(11) NOT NULL COMMENT 'Primary key; refers to {node}.nid.',
// plain_text_field VARCHAR(32) COMMENT 'Just a plain text field.',
// numeric_field INT(11) COMMENT 'Just a numeric field.',
// boolean_field INT(1) COMMENT 'Just an on/off field.',
// timestamp_field INT(8) COMMENT 'Just a timestamp field.',
// PRIMARY KEY(nid)
// );

тогда хук будет выглядеть так:

<?php
//Определям группу для таблицы 
// ['example_table'] - имя нашей таблицы, 
// ['table'] - означает что мы задаем настройки для подключения таблицы
// ['group'] - означает задаем название группы
 
$data['example_table']['table']['group'] = t('Example table');

 
 

//этот параметр не обязателен
 // если необходимо определяем таблицу как базовую,
// если этот параметр присутствует то на странице admin/build/views/add в View type: появиться еще один чекбокс с вашей таблицей
// указанная таблица будет являтся базовой, а это означает, при поставлении запросов другие таблицы будут JOIN -ится к ней
// в большенстве случаев ваша таблица должна быть связана с таблицами 'users' или 'node' или др, тогда этот параметр лучше не указывать 
   
$data['example_table']['table']['base'] = array(
     
'field' => 'nid',
     
'title' => t('Example table'),
     
'help' => t("Example table contains example content and can be related to nodes."),
     
'weight' => -10,
   );
 

//указываем к какой таблице JOIN иться нашей
   
$data['example_table']['table']['join'] = array(
// 'node' - означает имя таблицы, которая является базовой, елси вместо 'node' указать допустим 'users',
// то чтобы увидеть настроки для этого поля на странице admin/build/views/add в View type: необходимо поставить чекбокс
// напротив "Пользователь"
// 'left_field' и 'field' -  поля по которым будет производиться JOIN 
// 'left_field' - первичный ключ базовой таблицы, в данном случае node
// 'field' - поле нашей таблицы
     
'node' => array(
       
'left_field' => 'nid',
       
'field' => 'nid',
     ),
   );
 
 
// Дальше производим подключение остальных полей нашей таблицы
 // параметы будут иметь вид:
// ['example_table'] - имя нашей таблицы, 
// ['****'] - имя столбца нашей таблицы
// здесь добавлям для каждого поля свои подпараметры, которые соотвествуют настрокам во views:
// 'relationship', 'arguments', 'field', 'sort', 'filter', у которых указываются свои подпараметры
 
   // Node ID field.
   
$data['example_table']['nid'] = array(
     
'title' => t('Example content'),
     
'help' => t('Some example content that references a node.'),
// Так, как поле nid в нашей таблице является внишним ключем для таблицы {node} мы можем настроть relationship
// для этого поля.
     
'relationship' => array(
       
'base' => 'node',
       
'field' => 'nid',
       
'handler' => 'views_handler_relationship',
       
'label' => t('Example node'),
     ),
   );
 
 
// дальше идут примеры полей различного типа
   // текстовое поле.
   
$data['example_table']['plain_text_field'] = array(
     
'title' => t('Plain text field'),
     
'help' => t('Just a plain text field.'),
     
'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['example_table']['numeric_field'] = array(
     
'title' => t('Numeric field'),
     
'help' => t('Just a numeric field.'),
     
'field' => array(
       
'handler' => 'views_handler_field_numeric',
       
'click sortable' => TRUE,
      ),
     
'filter' => array(
       
'handler' => 'views_handler_filter_numeric',
     ),
     
'sort' => array(
       
'handler' => 'views_handler_sort',
     ),
   );
 
   
//  boolean поле.
   
$data['example_table']['boolean_field'] = array(
     
'title' => t('Boolean field'),
     
'help' => t('Just an on/off field.'),
     
'field' => array(
       
'handler' => 'views_handler_field_boolean',
       
'click sortable' => TRUE,
     ),
     
'filter' => array(
       
'handler' => 'views_handler_filter_boolean_operator',
       
'label' => t('Published'),
       
'type' => 'yes-no',
     ),
     
'sort' => array(
       
'handler' => 'views_handler_sort',
     ),
   );
 
   
//  timestamp поле.
   
$data['example_table']['timestamp_field'] = array(
     
'title' => t('Timestamp field'),
     
'help' => t('Just a timestamp field.'),
     
'field' => array(
       
'handler' => 'views_handler_field_date',
       
'click sortable' => TRUE,
     ),
     
'sort' => array(
       
'handler' => 'views_handler_sort_date',
     ),
     
'filter' => array(
       
'handler' => 'views_handler_filter_date',
     ),
   );
 
   return 
$data;
 }

?>

*Если вы создали файл ***.views.inc после того как включили модуль, то чтобы views его увидел достаточно почистить кеш на стрнанице admin/build/views/tools

как видите во всех полях указан параметр handler - это обработчик который будет отрабатывать поля при выбранном действии.
В данном примере обработчики используются стандартные views -овские,
почитать документацию про стандартные обработчики можно здесь
так же можно с помощью хуков и ООП изменять обработчики
для этого:
в "handler" указываем следующее значение: ищем подходящий обработчик в документации и указываем вместо views_ имямодуля_,
для примера: вместо views_handler_filter_date, пишем example_handler_filter_date
затем указываем файл обработчика, используя hook_views_handlers():

<?phpfunction hook_views_handlers() {
  return array(
//указываем путь к файлу обработчика (только папку, в которой он лежит)
    
'info' => array(
      
'path' => drupal_get_path('module''example') .'/includes',
    ),
// в данном случае в папке "includes" должен лежать файл example_handler_filter_date.inc, содержащий обработчик
    
'handlers' => array(
      
'example_handler_filter_date' => array(
        
'parent' => 'views_handler_filter_date',
      ),
    ),
  );
}
?>

Про то, что должен содержать файл с обработчиком и другие hook-и views напишу в следующей статье.

ЗЫ: Если есть недочеты, надуюсь гуру поправят

Комментарии

Аватар пользователя dfndr dfndr 10 ноября 2015 в 11:46

Не так давно "дружил" свой модуль с Views. К моему несчастью у меня PostgreSQL и необходима сортировка и фильтрация по дате... После выполнения такой фичи я понял одно обстоятельство -- почему везде в табличках народ для даты использует integer вместо `timestamp' или `date' postgresql-льных. К сожалению я не имел возможности переделать таблицы. Этому мешала довольно нетривиальная логика на pl/pgsql встроенной процедуре (аналогичная на php работала в 15-20 раз медленнее или я такой php-пист Smile ). Вобщем как бы там ни было сделал я так:
1) Postgresql позволяет создавать явные и неявные пользовательские преобразования. Делаем таковые для timestamp и timestamptz (см psql_ass_time_cast.sql.txt)

\SET ON_ERROR_STOP

BEGIN;

-- This CAST is needed for VIEWS. Views timestamp
-- operators dosn't have any compatability with PSQL.

DROP FUNCTION IF EXISTS timestamp_to_int(TIMESTAMP) CASCADE;

CREATE OR REPLACE FUNCTION timestamp_to_int(TIMESTAMP)
RETURNS BIGINT
AS $timestamp_to_int$
SELECT CAST(EXTRACT(epoch FROM $1) AS BIGINT);
$timestamp_to_int$ LANGUAGE SQL stable;

DROP FUNCTION IF EXISTS timestamp_to_int(timestamptz) CASCADE;
CREATE OR REPLACE FUNCTION timestamp_to_int(timestamptz)
RETURNS BIGINT
AS $timestamp_to_int$

SELECT CAST(EXTRACT(epoch FROM $1) AS BIGINT);
$timestamp_to_int$ LANGUAGE SQL stable;

DROP CAST IF EXISTS (TIMESTAMP AS INTEGER);
DROP CAST IF EXISTS (TIMESTAMP AS BIGINT);
CREATE CAST (TIMESTAMP AS BIGINT)
WITH FUNCTION timestamp_to_int(TIMESTAMP)
AS IMPLICIT;

DROP CAST IF EXISTS (timestamptz AS INTEGER);
DROP CAST IF EXISTS (timestamptz AS BIGINT);
CREATE CAST (timestamptz AS BIGINT)
WITH FUNCTION timestamp_to_int(timestamptz)
AS IMPLICIT;

COMMIT;

2) Перегрузил в views_handler_field_date 2 ф-и: query() и render() (файл в атачах people_advertisement_view_hd_date.inc.txt)

<?php                                                                                                                          
class people_advertisement_view_hd_date extends views_handler_field_date {                                                                 
    function 
query() {                                                                                                                     
        
$this->ensure_my_table();                                                                                                          
        
$this->field_alias $this->table_alias."_".$this->real_field;                                                                     
        
$this->query->add_field($this->table_alias,$this->real_field."::int8",$this->field_alias);                                         
                                                                                                                                           
    }                                                                                                                                      
    function 
render($values) {                                                                                                             
        
$our_date date("Y-m-d",$values->{$this->field_alias});                                                                           
        return 
format_date($values->{$this->field_alias},'small');
    }                                                                                                                                      
}                                                                                                                                          
?>

Может кому понадобится Smile

PS. Обращаю внимание на использование int8 (или он-же bigint ).

Аватар пользователя Gingervm Gingervm 20 декабря 2010 в 17:24

У меня такой вопрос - я хочу отображать данные, делать запросы и т.д. из таблиц своей базы, которая отдельно от друпала создана на mysql, соответственно я ее прописала в настройках и теперь как я поняла могу к ней обращаться с помощью функции
db_set_active('mydb');

но мне не очень понятно что мне в таком случае использовать в качестве базовой таблицы? мне нужно отдельно создать какую-то таблицу в моей базе и использовать ее в качестве базовой или как-то использовать уже существующие таблицы моей базы?

и еще что это за функция t( ) ?

заранее спасибо за помощь.

Аватар пользователя graker graker 20 декабря 2010 в 17:41

Привет вам теперь здесь Smile

Функция t() предназначена для перевода строк. Если вы в php-коде модуля или темы напишете t('English text'), то фраза English text станет доступна для перевода. Включите модуль locale - и сможете перевести ее на другие установленные на вашем сайте языки.
Иными словами, фраза, переданная на страницу через t(), будет отображена на языке, который установлен активным (для сайта или пользователя). При условии, что для данной фразы имеется перевод, конечно.

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

Аватар пользователя Gingervm Gingervm 20 декабря 2010 в 18:48

да, привет))

я все таки никак не пойму суть базовой таблицы в друпале, насколько я поняла это таблица, которую друпал может отображать, а по какому вообще принципу выбиралась базовая таблица или нет, ну вот та же node - она является базовой для материалов, почему она, а не какая-то другая или суть в том что в ней хранятся основные сведения по материалам сайта?. это я может чушь конечно спрашиваю, но по мне тогда хоть все таблицы сделать базовыми и не джойниться никуда. по тем примерам, которые я смотрела с join - это типа как установление связи между таблицами, но тогда если я например к той же node хочу присоединить свою какую-то таблицу, то у нее должно быть поле типа nid, по которому я буду связываться с полем nid таблицы node. а если нет у меня такого поля....

Аватар пользователя graker graker 20 декабря 2010 в 23:54

Вот повторюсь, ей богу, судя по написанному - не надо вам ваши таблицы хранить в отдельной базе. Переносите в друпальную, джойните к node и будет счастье Smile

А вообще - очень рекомендую отвлечься от попыток решить непонятную задачу в лоб и попробовать освоить основы Друпала по разным статьям, мануалам, книжкам и - господипрости - видеоурокам. А потом вернуться со свежими мыслями.

И эта. Базовая таблица - это понятие не "в друпале", а всего лишь в модуле Views.

Аватар пользователя Gingervm Gingervm 21 декабря 2010 в 21:58

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

Аватар пользователя graker graker 21 декабря 2010 в 22:32

Толковое про вьюс - с той статьи, что вы комментировали у меня в блоге есть ссылка. Даже две.

Про модули и хуки - сначала на d.org мануал по созданию модулей, потом все пордряд - можно API, можно Вандюка и т.д. Но лучше бы с простого начать, а не сразу в интеграцию Views ломиться.

Что касается технического задания - если его нельзя оспорить, значит вам придется либо написать заново кучу велосипедов, либо не использовать views вовсе.

Аватар пользователя yustos.com yustos.com 10 ноября 2015 в 11:47

Огромное спасибо! Свел воедино что нашел про views API здесь, на http://druit.ru/blogs/views/143, на http://graker.ru/drupal/papers/views_integration и на http://habrahabr.ru/blogs/drupal/80663/ и сделал pdf. У себя еще добавил чуток выдержек из буржуинов. Так удобнее, по-моему! Еще раз спасибо всем авторам!