Как подружить свой тип данных с Views

При разработке модулей для Drupal мы частенько создаем программно новые типы материалов (то есть нод). В процессе иногда возникает соблазн быстренько запрограммировать вывод какой-нибудь отсортированной коллекции этих материалов. Например, вывод нод-городов, отсортированных по алфавиту, или по древности, или сгруппированных по странам. Таких полезных коллекций может образоваться достаточно много и программно создавать каждую из них — не очень эффективно. Особенно если впоследствии нам захочется что-то поменять, объединить, или переделать. Гораздо аккуратнее — использовать модуль Views.

Вообще говоря, Views — один из краеугольных камней разработки на Drupal. Хотите помесячный архив нод? Views. Хотите вывести только заголовки и даты нод? Views. Хотите вывести ноды, сгруппированные по именам авторов? Views. Хотите получить список IP, с которых пользователь Василий заходил на сайт в течение Великого поста? Тоже Views. Один из самых популярных ответов на вопрос «Как в Друпале сделать…» — Views. Так что, чем быстрее разработчик подружится с этим прекрасным модулем — тем лучше. Для этого, кстати, есть неплохой мануал на английском языке: http://views-help.doc.logrus.com/.

Однако как только разработчик захочет получить с помощью Views коллекцию созданных им данных — например, из самодельной таблицы, сделанной для нового типа материала — он обнаружит, что Views еще не знает о его таблице. Так вот, раз и навсегда рассказать о своей таблице модулю Views — на мой взгляд, гораздо более правильное решение, чем программировать вручную все необходимые представления.

Далее — о том, как это сделать.

Предполагаю, что читатель уже умеет программно создавать свои типы материалов. Рассказывать буду на примере модуля, в котором новый тип уже создан. А чтобы не публиковать код модуля с описанием нового типа, предлагаю просто его скачать:
Скачать модуль mytest.
В модуле уже реализовано все, о чем дальше пойдет речь в заметке.

Итак, у нас есть тип материала testnode, в который мы добавили два целочисленных поля — int_count и int_total, хранящиеся в таблице БД {testnode}. Научим Views загружать эти поля из базы данных, выводить их, а также сортировать и фильтровать по ним коллекцию.

Перво-наперво, доложим Views о том, какую версию API мы используем (а используем мы версию Views 2.8 с Drupal 6.x). Для этого добавим в наш файл mytest.module вызов хука hook_views_api:

function mytest_views_api() {
  return array('api' => 2);
} //mytest_views_api

Затем создадим файл mytest.views.inc, в котором модуль Views самостоятельно сможет найти вызов нужных хуков. Пришла пора рассказать Views про нашу таблицу. Для этого используется хук hook_views_data(), возвращающий массив с информацией об описываемых таблицах и их полях. Реализация хука должна возвращать ассоциативный массив формата $data['имя_таблицы']['имена_полей']. Также в массиве для каждой таблицы может содержаться подмассив $data['имя_таблицы']['table'] с общей информацией о таблице. Рассмотрим хук по порядку:

function mytest_views_data() {
  $data = array();

  $data['testnode'] = array(
    'table' => array(
      'group' => t('Testnode'),
    ),
    //...

Подмассив ['table'] содержит основную информацию о таблице. Элемент ['group'] — это имя группы, в которой объявляемые нами поля появятся в выпадающих списках Views. В принципе, можно указывать имя группы для каждого описываемого поля, но если этого не делать — имя группы унаследуется из секции ['table'].

Прежде чем перечислять поля таблицы {testnode}, небольшое лирическое отступление о Views. Что, собственно, делает модуль Views, когда пользователь указывает в его удобных, хотя и запутанных на первый взгляд колонках интерфейса аргументы, фильтры, поля, отношения и способы сортировки? Правильно, модуль Views по заданным настройкам составляет SQL-запрос, вытягивающий из базы данных те данные, которые пользователь указал, и сортирует их так, как пользователю надо. Так что, чтобы пользователь мог указывать во Views поля таблицы {testnode}, нужно рассказать модулю Views, что он должен вставлять в SQL-запрос.

Для каждого поля нашей таблицы мы можем указывать следующую информацию:

  • ['title'] — заголовок поля, таким он будет показан пользователю в интерфейсе Views;
  • ['group'] — если хочется, можем указать для поля группу, отличную от указанной в ['table'];
  • ['help'] — здесь можно задать текст подсказки по данному полю, который пользователь увидит мелким шрифтом рядом с заголовком;
  • ['real field'] — если в массиве $$data мы в качестве ключа указали для данного поля синоним, то в ['real field'] нужно привести настоящее название поля в таблице БД.

Перечисленные элементы — заголовок, помощь, группа — имеют скорее декоративное назначение. Кроме них нам нужно заполнить элементы массива, имеющие непосредственное отношение к логике работы Views. Это элементы ['field'], ['filter'], ['sort'], ['argument'] и ['relationship'], отвечающие соответственно за чтение поля из БД, фильтрацию поля (с помощью WHERE), сортировку поля (ORDER BY), использование поля в качестве аргумента (в URL) и отношения (то есть присоединение другой таблицы через данное поле). Все пять элементов должны быть ассоциативными массивами. В них нужно обязательно привести значение элемента ['handler'], а также, по необходимости, дополнительные элементы, которые могут варьироваться в зависимости от значения ['handler'].

Здесь нужно еще одно лирическое отступление. В отличие от ядра Друпала и большинства сторонних модулей, API модуля Views — объектно-ориентированный (насколько это возможно). Товарищей, привыкших программировать под Друпал, Views API может несколько смутить, но смею заверить: это плюс, а не минус. Кстати, по поводу отсутствия объектно-ориентированного подхода в «капельке» разные граждане периодически поднимают бучу. Автор статьи, однако, относится к этой особенности безразлично и принимает ее как данность, с которой нужно работать, а не хаять почем зря.

Рассмотрение объектно-ориентированной модели Views API, в принципе, должно быть темой отдельной большой статьи. Поэтому здесь коснемся только того, что нас непосредственно волнует, то есть хэндлеров. Понимающий английское письмо читатель может ознакомиться с подробным описанием Views API на сайте: http://views2.logrus.com/doc/html/index.html.

Корнем модели является класс views_object, а уже от него наследуется класс views_handler. Ветка производных от views_handler классов управляет поведением заданных пользователем элементов представления (аргументов, полей, фильтров и так далее). То есть хэндлеры — это управляющие классы, задача которых следить, чтобы все что нужно было добавлено в запрос, чтобы из БД был получен нужный результат, чтобы был сгенерирован правильный текст поля и так далее. Таким образом, чтобы пользователь мог использовать поля из таблицы {testnode} для генерации своих представлений, нужно указать для каждого поля правильные классы-хэндлеры.

Хэндлеры бывают очень разные в зависимости от типа данных, необходимого эффекта, оказываемого ими на запрос, сложности фильтра, который мы хотим использовать и тому подобное. Для нашего тестового модуля нам понадобятся хэндлеры views_handler_field (для вставки в запрос обычного поля), views_handler_filter_numeric (чтобы в фильтре можно было пользоваться значением поля как числом) и views_handler_sort (обычный хэндлер для сортировки ASC/DESC без извратов). В результате поля таблицы {testnode} мы опишем так:

    //... это продолжение хука mytest_views_data
    'tid' => array(
      'title' => t('Test Node ID'),
      'field' => array(
        'handler' => 'views_handler_field',
      ),
      'filter' => array(
        'handler' => 'views_handler_filter_numeric',
      ),
    ),
    'nid' => array(
      'title' => t('Node ID'),
      'field' => array(
        'handler' => 'views_handler_field',
      ),
      'filter' => array(
        'handler' => 'views_handler_filter_numeric',
      ),
    ),
    'int_count' => array(
      'title' => t('Count'),
      'field' => array(
        'handler' => 'views_handler_field',
      ),
      'sort' => array(
        'handler' => 'views_handler_sort',
      ),
      'filter' => array(
        'handler' => 'views_handler_filter_numeric',
      ),
    ),
    'int_total' => array(
      'title' => t('Total'),
      'field' => array(
        'handler' => 'views_handler_field',
      ),
      'sort' => array(
        'handler' => 'views_handler_sort',
      ),
      'filter' => array(
        'handler' => 'views_handler_filter_numeric',
      ),
    ),
  );

Теперь необходимо снова вернуться к секции ['table'] массива $data['testnode']. Помимо имени группы, в ней содержится важная информация о том, базовая ли это таблица, или ее нужно присоединять к другой при генерации представления. Базовая таблица — это таблица, центральная для Views, как например таблица node для Node view или таблица user — для User view. Будь наша таблица базовой, мы задали бы для нее в массиве $data['имя_таблицы']['table']['base'] элементы ['field'] (название поля-первичного ключа), ['title'] (заголовок таблицы), ['help'] (текст подсказки) и ['database'] (информация о базе данных, если таблица находится не в базе Друпала).

Но в рассматриваемом примере таблица не базовая, поэтому рассмотрим другой массив — $data['имя_таблицы']['table']['join']. В нем мы должны привести информацию о том, как и к какой базовой таблице Views должен присоединить данные таблицы {testnode}:

//join to node
  $data['testnode']['table']['join']['node'] = array(
    'left_field' => 'nid',
    'field'     => 'nid',
  );

  return $data;
} //function mytest_views_data

Поскольку в нашей таблице содержатся поля для нового типа ноды testnode, очевидно, что мы хотели бы присоединить их к таблице {node}, так чтобы поля int_count и int_total могли выводиться в Node View. Для этого в секции ['join'] мы создаем массив ['node'] (имя базовой таблицы) и указываем поля, на базе которых можно объединить данные: 'left_field' — поле в таблице {node} и 'field' — поле в таблице {testnode}. Таблицы, как видно из кода, объединяются на базе поля nid.

На этом интеграция таблицы {testnode} закончена. Модуль можно установить и Views сразу позволит добавлять к представлению поля int_count и int_total, а также сортировать и фильтровать по их значениям вывод представления.

Теперь же решим задачу добавления к «вьюхе» виртуального, то есть несуществующего в таблице {testnode} поля. Пусть оно называется percentage и вычисляется из существующих значений int_count и int_total по формуле (int_count*100/int_total), то есть представляет собой некое процентное соотношение count от total. На этом примере посмотрим, как добавить виртуальное поле во Views, как пользоваться хэндлерами с суффиксом formula и как писать свои унаследованные от существующих хэндлеры.

Во-первых, нам необходимо добавить поле percentage, для чего, как мы уже знаем, служит элемент ['field']:

  //... продолжение хука mytest_views_data
  $data['testnode']['percentage'] = array(
    'title' => t('Percentage'),
    'field' => array(
      'handler' => 'mytest_handler_field_percentage',
    ),
  //...

Очевидно, мы не можем использовать стандартный field-хэндлер, поскольку он добавит в SQL-запрос поле 'percentage', а в таблице {testnode} такого поля нет. Вместо этого мы бы хотели ничего не добавлять в запрос, а на выходе получить результат в виде числа. Для этого нам потребуется собственный хэндлер, который мы назовем mytest_handler_field_percentage. Общепринятая практика при программировании под Views рекомендует, чтобы первым словом в названии хэндлера было имя модуля, затем слово handler и та опция Views, которой он управляет (то есть field), и в конце название поля таблицы БД. Реализацию хэндлера разместим в файле mytest_handler_field_percentage.inc:
<?php
/**
 * Класс генерирует виртуальное поле, равное round(int_count*100/int_total);
 */

class mytest_handler_field_percentage extends views_handler_field_numeric {
  function query() {
    return ;
  }
  function render($values) {
    if (isset($values->testnode_int_count) && isset($values->testnode_int_total)) {
      return round($values->testnode_int_count*100/$values->testnode_int_total);
    } else {
      return 0;
    }
  }
}

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

Затем озаботимся результатом, который будет записан в поле после выполнения запроса Views. За это отвечает метод render($values), где в объекте $values находятся все считанные из БД значения. В переопределенном методе render() мы вычисляем и возвращаем результат по считанным из базы полям int_count и int_total. Обратите внимание, что имя таблицы {testnode} является префиксом для обоих полей. Если же int_count или int_total не были считаны из БД при выполнении запроса, метод render() вернет 0. Правда, такой подход подразумевает, что пользователь должен вручную добавить поля int_count и int_total к представлению. Если мы захотим автоматизировать процесс и добавлять эти поля всякий раз, когда нам нужно поле percentage, то необходимо реализовать метод add_additional_fields(), либо добавить поля int_count и int_total в свойство additional_field в конструкторе хэндлера, либо добавить их к запросу непосредственно в методе query().

Теперь, когда новое виртуальное поле описано, мы бы хотели иметь возможность сортировать по нему коллекции данных. Для этого подходит уже существующий хэндлер views_handler_sort_formula. Этот хэндлер дополнительным параметром требует формулу, по вычисленному значению которой будет отсортирована коллекция. Заданная формула будет вставлена в запрос Views в части ORDER BY.

  //... продолжение массива $data['testnode']['percentage']
  'sort' => array(
      'handler' => 'views_handler_sort_formula',
      'formula' => 'ROUND(testnode.int_count*100/testnode.int_total)',
    ),
  //...

Еще мы хотели бы научить Views фильтровать выборку из БД по виртуального полю percentage. Для этого тоже создадим новый хэндлер:

  //...
    'filter' => array(
      'handler' => 'mytest_handler_filter_percentage',
    ),

Хэндлер mytest_handler_filter_percentage разместим в одноименном .inc-файле. Наследовать его будем от numeric-фильтра:
class mytest_handler_filter_percentage extends views_handler_filter_numeric {
  function query() {
    $this->ensure_my_table();
    $field = "ROUND(testnode.int_count*100/testnode.int_total)";

    $info = $this->operators();
    if (!empty($info[$this->operator]['method'])) {
      $this->{$info[$this->operator]['method']}($field);
    }
  }
}

Здесь мы переопределяем метод query() чтобы вместо названия поля в WHERE-часть запроса была добавлена наша формула. Для этого мы сначала вызовом $this->ensure_my_table() убеждаемся в том, что в запрос будет добавлено имя таблицы, в которой находятся поля int_count и int_total, затем определяем операцию, по которому происходит фильтрация, и указываем для этой операции нашу формулу. Смысл наследования numeric-фильтра в том, что для него уже определены операции сравнения чисел (больше, больше или равно, меньше и так далее). По сути, реализация метода скопирована из реализации родителя, изменить потребовалось только значение $field.

Наконец, прежде чем Views увидит наши новые хэндлеры, необходимо добавить в файл mytest.views.inc реализацию хука hook_views_handlers:

function mytest_views_handlers() {
  $handlers = array();
 
  $handlers['handlers']['mytest_handler_field_percentage'] = array(
    'parent' => 'views_handler_field_numeric',
    'file' => 'mytest_handler_field_percentage.inc',
  );
 
  $handlers['handlers']['mytest_handler_filter_percentage'] = array(
    'parent' => 'views_handler_filter_numeric',
    'file' => 'mytest_handler_filter_percentage.inc',
  );
 
  return $handlers;
} //function mytest_views_handlers

Хук просто возвращает массив новых хэндлеров с информацией о том, какие классы-хэндлеры они наследуют и в каких файлах их искать.

Вот и все. Мы научили Views считывать, выводить и использовать для сортировки и фильтрации результатов запроса виртуальное поле percentage. Осталось только почистить кэш Views со страницы 'admin/build/views/tools' и модуль готов к работе. Задача решена.

Прикрепленный файлРазмер
mytest.tar.gz3.18 кб
allexx (гость)
Аватар пользователя allexx

Спасибо за статью. Для меня это послужило отправной точкой. За выходные более менее вник в азы и сам тоже небольшую заметку выложил по этой теме: http://www.allexx.info/drupal_views_api_1st_example

graker
Аватар пользователя graker

Пожалуйста. К сожалению, информация по Views API очень скудная не только на русском, но и на английском. Поэтому видимо инициативные пользователи Друпала должны сами стараться писать всякое про Views, чтобы набралась критическая масса статей. Тогда общими стараниями мы приблизимся к светлому будущему :)

Vladimir (гость)
Аватар пользователя Vladimir

Поскольку нет инфы о апи, очень помогает разбор инклудов в /views/modules, например из /views/modules/node.views.inc я узнал как выводить поле ввиде даты.

graker
Аватар пользователя graker

Вообще, по API есть информация, в заметке есть ссылки на нее.
Правда, некоторые вещи там не до конца описаны или вовсе не описаны, да, поэтому приходится выискивать их в коде.

vic (гость)
Аватар пользователя vic

А работали с числовыми полями, которые являются ключами от массива значений?
Например хранится в базе поле статус. Но мне при работе со views хочется видеть не сухие цифры, а их значения:
array(
'1' => 'Проект',
'2' => 'На согласовании',
'3' => 'Активный',
'4' => 'Закрыт',
'5' => 'Архив',
);

Почитал документацию по API - вобще скудно

graker
Аватар пользователя graker

Навскидку - через свой филд-хэндлер и метод render() легко делается, примерно так:

class mytest_handler_field_array_key extends views_handler_field {
  function render($values) {
    if (isset($values->my_array_key)) {
      return $my_array[$values->my_array_key];
    }
  }
}

vic (гость)
Аватар пользователя vic

Спасибо за помощь!
Но что то не работает. Во вьюсах вылазит ошибка
"Error: handler for question > status doesn't exist!"

А попутно у меня еще задача выросла. Мне нужно добавить к вьюсам виртуальное поле, которое представляет собой сумму связанных полей из другой таблицы. Например, есть вопрос, а к нему надо добавить виртуальное поле - количество ответов для этого вопроса.
Это нужно опять же свой хендлер и определить там как то функцию function query() ?

graker
Аватар пользователя graker

vic пишет:
Спасибо за помощь!
Но что то не работает. Во вьюсах вылазит ошибка
"Error: handler for question > status doesn't exist!"
Я навскидку написал, не знаю, может вы хэндлеры не так задали или еще чего.

Цитата:
Это нужно опять же свой хендлер и определить там как то функцию function query() ?
Ага, query() и render().

andypost (гость)
Аватар пользователя andypost

Насчет документации views - все основы изложены в самом модуле, просто нужно поставить модуль advanced_help

graker
Аватар пользователя graker

Да я как-то в курсе. Речь про особенности API, а не про работу с модулем.

andypost (гость)
Аватар пользователя andypost

Дык там и особенности API расписаны, как и для панелей.

graker
Аватар пользователя graker

Угу. Там копия вот этого: http://views-help.doc.logrus.com/. Ну или наоборот, по адресу - копия advanced_help-а по Views :) По мне, так для работы с API этого не совсем достаточно. Вот тут получше: http://views2.logrus.com/doc/html/index.html, но тоже мало и недоработано, в куче мест просто куски кода, без какого-либо описания логики.

Dark (гость)
Аватар пользователя Dark

Спасибо за статью! Помогла добавить поля во вьюс
Сижу разбираюсь с модулями Views, в частности с хэндлерами таксономии. У меня есть свой тип материала, с полями использующих словарь, но они на созданную ноду не цепляются, т.е. как термины к ноде. Подключил хэндлер "views_handler_field_term_node_tid", но ясное дело не работает.
Как можно отладить это дело, чем-нибудь пользуетесь, coder, devel?

graker
Аватар пользователя graker

Иногда пользуюсь девелом, иногда просто вывожу в хендлере нужные данные через print_r().
Так или иначе, мне описание проблемы не понятно. Какие-то поля используют словарь но почему-то терминами таксономии не являются. Почему? И в то же время вы используете хэндлер id терминов, хотя это не термины. Почему? И почему нельзя использовать просто таксономию?

Без ответов на эти вопросы понять что-то затруднительно :)

Dark (гость)
Аватар пользователя Dark

Спасибо что так быстро откликнулись!

Попробую объяснить. Я создал поле, используя api модуля hierarchical_select, т.е. это список "страна-область-город". Почему выбранный термин не становится термином ноды я не знаю (надо будет почитать еще раз апи этого селекта). В таблице я храню tid термина, поэтому и решил что правильнее будет использовать хэндлер с tid. Я понимаю что поле не является термином ноды, но как же его тогда вставить во Views? Придется писать свой обработчик?

Для вывода в hook_views я использовал taxonomy_get_term($tid). Как подключить поле, чтобы оно являлось термином ноды?

graker
Аватар пользователя graker

Я наверное чего-то решительно не понимаю, но считаю, что решать проблему надо через корректную интеграцию с таксономией. Тогда все вьюсы автоматически заработают. Там ведь не сложно вроде, я программно термины и создавал, и сохранял, и к нодам добавлял без проблем (правда, без h_select-а). В общем, думаю, что правильнее всего вам будет добить h_select, чтобы термин сразу добавлялся к ноде - и все решится.

И зачем вы где-то в своей таблице храните tid термина, когда для этого есть таблица {term_node}? Храните в ней - это ведь и есть добавление термина к ноде :)

Ingumsky (гость)
Аватар пользователя Ingumsky

Решил я тоже заняться решением задачи, завязанной на views, а потому требовавшей более глубокого понимания views api. В результате пришёл к твоей статье, но задачу всё равно не решил :) Вполне возможно, что я просто не те средства использую для решения своих задач.

Смотри, есть views, который выводит список нод в хронологическом порядке. Я хочу дать пользователям возможность пользоваться exposed фильтром с датами, но при этом сделать определённые ограничения. Хочу, чтобы они могли с его помощью «скакать» по определённым временным отрезкам. Каждый отрезок начинается 1 июля одного года и заканчивается 1 июля следующего. Поэтому мне нужно было жёстко связать два поля фильтра («от» и «до») и привязать их к первому июля, позволив пользователю выбирать только год. Я долго думал, как мне это решить и не придумал ничего лучше, чем создать свою таблицу в БД, в которой задать начальную и конечную даты этого периода, а потом сделать привязку exposed filter к выборке из этой таблицы так, чтобы поле «от» фильтра было больше start_date моей таблицы, а поле «до» было меньше поля «end_date» моей таблицы.

Но, судя по всему, сделать такую привязку не получится. Моя таблица периодов не может быть 'join' (ей не к чему джойниться), а 'base', вроде как для этого случая не подходит, или я просто не понимаю, как его в данном случае связать с моей выборкой нод. Через дополнительный views? Через relatioships?

graker
Аватар пользователя graker

Хы. Извращенный конечно способ, но навскидку ничего в голову не приходит. А ты не искал модулей-расширений для работы с датами во views? Не исключено, что есть.

А вообще, таблица тут как-то не к месту. Может, попробовать свой фильтр-хэндлер написать?

Ingumsky (гость)
Аватар пользователя Ingumsky

Я ещё раньше искал для другой задачи — хотел сделать через views блок типа On this day, но так ничего и не нашёл.

Таблица не к месту, но мне всё равно хотелось попробовать её вывести во views, чтобы посмотреть, как это делается :) Оказалось, что это довольно просто, хотя поля типа дата у меня views пока отказывается распознавать даже несмотря на наличие views_handler_field_date, указанного в качестве хендлера поля, и показывает мне все даты как 1 января 1970 :)

А так, видимо, действительно придётся думать о своём хендлере, иначе какая-то ерунда получается :)

graker
Аватар пользователя graker

Да хэндлеры не очень сложно делать, не боись. А как научишься - сразу куча пользы :)

Ingumsky (гость)
Аватар пользователя Ingumsky

Пока у меня не очень срастается :) Тут вообще, как я понимаю, проблема следующая — views не очень-то дружен с датами, поэтому-то как раз у меня и не получилось в своё время сделать через него On this date — он не позволяет выставить в фильтре только число и месяц и делать выборку, опираясь на совпадение числа и месяца, но вне зависимости от года.

Собственно, та задача, которой я сейчас занимаюсь, имеет ту же проблему, но с обратной стороны. Мне важно, чтобы пользователь указывал год (причём только один), а остальные значения (число и месяц в дате «от» и полную дату в дате «до») я должен проставлять за него сам. Пока что у меня не очень получается это делать. Точнее — вообще не получается :)

Как ни странно, нет модулей для Друпала, которые решали бы хотя бы задачу on this date во views. Да и в сети как-то не особенно много описаний работы хендлеров с полями даты. Я нашёл только один рассказ: http://www.dave.st/content/creating-datetime-view-handler-views2 Парень под свои задачи написал хендлер, который обрабатывает DATETIME, который ему достался в наследство от Event. Но, если честно, я пока не сумел применить полученные от прочтения этой статьи знания, да и от других статей по хендлерам тоже.

К сожалению, документация не так хороша, как хотелось бы, поэтому приходится снова и снова копаться в чужом коде, чтобы постараться понять, что и как работает. Вот, например, мне совершенно непонятно до сих пор, как сделать обрабатывать своим хендлером только конкретные фильтры. Если это применять к своей таблице, «породнившейся» со views, это понятно — у тебя в статье как раз об этом. А если мне нужно «натравливать» свой фильтр на другие таблицы? Пока в документации я этого не встретил, хотя это должно быть в начале — ведь это одна из основ работы с API. В общем, вопросы, вопросы, вопросы.

graker
Аватар пользователя graker

Я б помог, но сейчас времени категорически нету, а в понедельник в отпуск уезжаю.
Но если разберешься - обязательно расскажи :)

Насчет натравливания хэндлера: в data-хуке ты можешь описать любую таблицу, а не только свою. Но пользоваться нужно осторожно.

Ingumsky (гость)
Аватар пользователя Ingumsky

Если разберусь (а я рассчитываю разобраться), обязательно расскажу :) И спасибо за подсказку по хендлеру :)

А ты куда и как надолго? Когда ждать обзора модулей? -)

graker
Аватар пользователя graker

В теплые страны, на две недели :) Потом напишу.

Обзор, надеюсь, будет завтра-послезавтра, хотя времени мало.

Ingumsky (гость)
Аватар пользователя Ingumsky

В тёплые страны? О-о-о. Хорошо. Завидую :) Я в этом году невыездной.

Gingervm (гость)
Аватар пользователя Gingervm

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

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

Gingervm (гость)
Аватар пользователя Gingervm

все, мой предыдущий вопрос отменяется - я не заметила кусок про присоединение базы, прошу прощения

graker
Аватар пользователя graker

Ничего страшного, бывает :)

А я уж было подумал - надо присоединить к Views таблицу, которая в другой БД находится, не с Друпалом.

Gingervm (гость)
Аватар пользователя Gingervm

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

Gingervm (гость)
Аватар пользователя Gingervm

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

graker
Аватар пользователя graker

Хм. Вроде можно, есть ключ 'database' для этого.

Скорее всего, нужно присоединять к базовой таблице {node} на основе nid. Но описание несколько сумбурное, а мне отсюда не видно, как у вас чего сделано :)

Базовая таблица - таблица, данные из которой могут отображаться во вьюхах сами по себе, без зависимостей от других таблиц. Базовые таблицы - это node, user и т.п. Если вы хотите создать совершенно новый тип представления - нужна базовая таблица. Если же нужно просто дополнить представление с материалами (пользователями, терминами таксономии) дополнительной информацией - присоединяйте таблицу к базовой, на базе которой ваше представление работает. Подсказка: если вы создали представление Node (то есть вывод материалов), базовая таблица будет {node}, если User (вывод пользователей) - то {user} и т.п.

Gingervm (гость)
Аватар пользователя Gingervm

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

graker
Аватар пользователя graker

В settings.php помимо дефолтной базы ($db_url['default']=...) добавить еще одну строчку для другой базы. Но это только для базовых таблиц подходит, а для присоединений надо чтоб таблицы в одной базе были.

Gingervm (гость)
Аватар пользователя Gingervm

в этом файле вот что написано по этому поводу:
* To specify multiple connections to be used in your site (i.e. for
* complex custom modules) you can also specify an associative array
* of $db_url variables with the 'default' element used until otherwise
* requested.

т.е. как я поняла тогда вместо

$db_url = 'mysqli://root@localhost/modb';
$db_prefix = '';

мне надо задать две переменные с url и сделать из них массив
$db_url = 'mysqli://root@localhost/modb';
$db_url1 = 'mysqli://root@localhost/mydb';

а как мне тогда описать массив из них? или тогда надо переменной $db_url присвоить массив из нескольких url?

graker
Аватар пользователя graker

  $db_url['default'] = 'mysqli://root@localhost/modb';
  $db_url['mynewbase'] = 'mysqli://root@localhost/mydb';

Как-то так.

Но мне почему-то кажется, что вы делаете нечто странное и лишнее. Действительно ли нужно хранить эту вашу таблицу в отдельной базе данных?

Gingervm (гость)
Аватар пользователя Gingervm

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

graker
Аватар пользователя graker

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

Gingervm (гость)
Аватар пользователя Gingervm

эх, попробую разобраться....

jedi (гость)
Аватар пользователя jedi

я подружил кое как пока через Table Wizard(галочками) с внешней таблицей.

$db_url['default'] = 'mysqli://root:mysql@localhost/_test'; //основная БД друпала
$db_url['transport'] = 'mysqli://root:mysql@localhost/transport' ; //другая БД, где находится наша автономная таблица

$db_prefix = array(
  'default' => '_test_',   // префикс таблиц _test_ у друпаловского движка
  'log' => 'transport.',   // внешняя таблица log без префиксов в базе transport
  'locales_source' => '_test._test_', // затычки для модуля Table Wizard
  'locales_target' => '_test._test_', // затычки для модуля Table Wizard
);
 

Теперь schema и views знаю про мою таблицу в другой бд, которая не пренадлежит друпалу

Гость (гость)
Аватар пользователя Гость

Вопрос:

А если мне надо что бы функция модифицировала запрос и вернула не в формате views_handler_field_numeric а обычный текст? Это значит надо писать что-то типа views_handler_field_text ? И в каком виде она должна возвращать return?

graker
Аватар пользователя graker

Не очень понимаю, о какой функции речь и кто эта «она».

Предположите на секунду, что мне неведомы ваши помыслы, что я не знаю ничего о вашей задаче — и попробуйте объяснить так, чтобы было понятно. Иначе я вряд ли смогу ответить что-то вразумительное.

Гость (гость)
Аватар пользователя Гость

Я понял, извините пожалуйста.

У меня есть определенный тип материала и мне надо вывести через Views некоторые его поля. Для того что бы их вывести нужно сформировать определенный запрос к БД, результатом которого будет текст или строчки, ну вообщем не цифры, поэтому extends views_handler_field_numeric не подходит нужно работать с текстом. Так вот меня интересует какие есть еще стандартные функции такие как views_handler_field_numeric, только для текста. Вот

graker
Аватар пользователя graker

А, ясно. Для текста подойдет просто views_handler_field.
А вообще — вот тут они все перечислены: http://views2.logrus.com/doc/html/index.html

Гость (гость)
Аватар пользователя Гость

Спасибо большое, буду добить)

Гость (гость)
Аватар пользователя Гость

Здравствуйте, а вот у меня вопрос.

А что если мне надо к определенному полю, которое выводиться через Views, прикрепить, допустим, количество записей в определенной таблице?

graker
Аватар пользователя graker

Посмотрите, как устроены вот эти модули:
http://drupal.org/project/views_groupby
http://drupal.org/project/views_calc

Гость (гость)
Аватар пользователя Гость

Спасибо большое! Сейчас буду разбираться)

Гость (гость)
Аватар пользователя Гость

Здравствуйте! а подскажите пожалуйста как можно экспортировать созданный мной вид Views вместе с модулем. Что бы вид устанавливался вместе с модулем. Спасибо

graker
Аватар пользователя graker

Делается это так.
Создаете свой собственный модуль и в нем сохраняете дефолтную вьюху как написано тут: http://views-help.doc.logrus.com/help/views/api-default-views.
Затем добавляете в зависимость к этому модулю тот, который нужно устанавливать вместе с.

Все, теперь установить вашу вьюху можно только с заданным модулем.

Гость (гость)
Аватар пользователя Гость

О! Спасибо! Разобрался) Работает.

А еще вопрос такой. Мне нужен фильтр Views что бы он отфильтровал выводимые данные по значению из URL. Ну то есть допустим заходим на страницу category/4 и он выдавал только материалы у которых в БД в столбце category стоит 4.

Спасибо

graker
Аватар пользователя graker

Это называется «аргументы».

Вы бы эта, по приведенным ссылкам прошли и прочитали все не урывками, а целиком и по порядку. И большинство вопросов отпало бы само собой.

Гость (гость)
Аватар пользователя Гость

Я, наверное, задаю очень глупые вопросы ответы на которые просто очевидны?

graker
Аватар пользователя graker

Какие-то — да, какие-то — нет. Одно дело вопросы про связь вьюхи с модулем или про количество записей — это нормальные вопросы, на них можно коротко ответить, мне не трудно.

Другое дело — вопросы, демонстрирующие незнание материальной части (как про аргументы). На такие вопросы я всегда отвечаю одинаково: предложением сэкономить время нам обоим и ознакомиться с документацией.

После чего всегда можно вернуться и задать другие, годные вопросы :)

Гость (гость)
Аватар пользователя Гость

Ясно. Ну тогда наверное вот это будет годный вопрос. Как создать свой views_handler_argument, а то что то вообще ничего не нашел на русском(

graker
Аватар пользователя graker

Так же как и другие хэндлеры — унаследовать views_handler_argument или views_handler_argument_numeric и изменить поведение там, где это требуется.

Посмотрите как это делается для уже существующих аргументов. Например, views/modules/user/views_handler_argument_user_uid.inc. Или прямо в код views_handler_argument_numeric.

Гость (гость)
Аватар пользователя Гость

Здравствуйте, у меня такая проблема.

У меня есть несколько материалов. Они были созданы не совсем правильно картинки к этим материалам были прикреплены через обычное atach files. Мне надо теперь перегнать как -то все эти картинки в CCK Image. как это можно сделать?

Спасибо.

graker
Аватар пользователя graker

Не знаю :)
Я бы вручную перегнал. Ну или курил бы устройство таблиц БД в CCK и писал код — смотря сколько материалов и картинок.

Гость (гость)
Аватар пользователя Гость

более 60 тыс =(

graker
Аватар пользователя graker

Значит — надо писать код для автопереноса.

Гость (гость)
Аватар пользователя Гость

Та. надо. Я вот думаю это будет как то так)
Надо сначала по вытаскивать адреса всех атаченых файлов, а потом их закинуть в ImageAPI. Как-то так)

Владимир (гость)
Аватар пользователя Владимир

Как добавить виртуальное поле считающее количество записей в некой таблице для данного материала?
Поле добавить получилось переопределением:

class lot_handler_field_counts extends views_handler_field {
  function render($values) {
     return db_result(db_query('SELECT count(bid) as counts from {lot_bids} where nid = %d',$values->nid));  
  }  
  function query() {
  }
}

Но возникает проблема при попытке сортировать по этому полю выдается ошибка что поле не найдено.
Подскажите пожалуйста. подробно я описал проблему здесь:
http://www.drupal.ru/node/61385

graker
Аватар пользователя graker

1. Вы сделали только хэндлер поля. Для сортировки нужно реализовать sort handler. Кроме того, поскольку у вас рендеринг идет отдельным запросом, а в query() вообще ничего нет, естественно что поле отсутствует и в запрос для сортировки не попадет никак. Ведь Views не сортирует данные после их считывания из БД, он сортирует их в ходе своего запроса.

2. Для этой задачи есть модуль. Если не ошибаюсь, Views Calc подходит.

Владимир (гость)
Аватар пользователя Владимир

1. Переопределил для поля

        'sort' => array(
                'handler' => 'lot_handler_sort_counts',
        ),

Я так понимаю просто formula тут не подойдет?...
Сделал связь:
  $handlers['handlers']['lot_handler_sort_counts'] = array(
    'parent' => 'views_handler_sort',
    'file' => 'lot_handler_sort_counts.inc',
  );

И создал отдельный файл.

class lot_handler_sort_counts extends views_handler_sort {
  function render($values) {
  }
  function query() {
    return ;
  }
}

Если я правильно понимаю то нужно переопределить функцию query() так как мы меняем запрос в разделе ORDER BY.
Но что то не пойму что в этом случае надо сюда писать... примеров таких не нашел.

2. Насчет модуля Views_calc - насколько я понимаю он считает итоги таблицы - то есть количество записей в нашем view. Тут же надо высчитать свое количество для каждой строки таблицы. Поправьте меня, если я ошибаюсь пожалуйста.

Владимир (гость)
Аватар пользователя Владимир

Вообще если просто писать запрос к базе, то:
1. К view (существующему запросу) надо присоединить таблицу
 INNER JOIN (SELECT nid, count(bid) as count FROM {lot_bids} GROUP BY nid) cnt ON cnt.nid = node.nid
2. Вывести поле
 cnt.count
3. И добавить сортировку
  ORDER BY cnt.count

Можете объяснить что из этого куда во Views нужно перенести, чтобы это все сгенерировалось.. не совсем понимаю связь...

graker
Аватар пользователя graker

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

Владимир (гость)
Аватар пользователя Владимир

1. Попробовал views_calc
Добавил Views_calc поле COUNT(%lot_bids.bid)
Добавляю поле во view.
Ругается так как нет GROUP BY блока. и где его добавить честно говоря непонятно
2. Попробовал views_group by
Все тоже самое получилось сделать - но проблема с сортировкой - Есть даже топик на эту тему (сортировать по вычисленному значению не получается) : http://drupal.org/node/529912 и http://drupal.org/node/1091456
Но видимо они пока проблему не рашают

Ольга (гость)
Аватар пользователя Ольга

Спасибо за ссылку на учебник по Views. Хотя и освоила этот модуль, Arguments и Relationships попрежнему остаются загадкой. И PHP ждёт своего часа. Эх, нелегко это - быть начинающим друпалером. :)

Ольга (гость)
Аватар пользователя Ольга

Прошу прощения, "по-прежнему".

graker
Аватар пользователя graker

Ольга пишет:
Хотя и освоила этот модуль, Arguments и Relationships попрежнему остаются загадкой. И PHP ждёт своего часа. Эх, нелегко это - быть начинающим друпалером. :)
Задавайте вопросы, Оля, ответим :)

Гость (гость)
Аватар пользователя Гость

Учусь щас работать с ним над своим сайтом

graker
Аватар пользователя graker

Зачем ты врешь?

Гость (гость)
Аватар пользователя Гость

Приветствую graker,

Помоги разобраться с проблемкой:

Имеем каталог недвижки построеной на nodehierarchy:

Тип (Термин) | ССК | ССК
Квартира | Площадь | Цена - самостоятельная квартира
Комплекс | (родительский объект)
Квартира | Площадь | Цена - квартира в комплексе (дочерний объект)
Квартира | Площадь | Цена - квартира в комплексе (дочерний объект)

Нужно сделать расширенный поиск по базе (в принципе все реализовано, но не нравится скорость выполнения)

Создал View:страница с аргументом "nid"

/result/площадь от/площадь до/цена от/цена до - так передаются параметры странице

аргументы обрабатываю своей функцией, которая делает несколько запросов к базе:
1. выбор nid удовлетворяющих условиям поиска для самостоятельных квартир
2. выбор nid для дочерних объектов
-- получение уникального списка родительских объектов
3. объединение результатов
4. передача списка nid'ов в аргумент views

Выводим все поля для каждого nid, если это самостоятельный объект, то поле этого объекта, если это комплекс, то для него выводим все дочерние объекты с ценой.

Теперь проблема с сортировкой
Создано поле PHP, которое если есть цена у объекта выводит ее, если нет то ищет минимальную цену в дочерних объекта (опять же используя условия поиска) и выводит ее. Ставлю возможность сортировать по этому полю, и получаю 1900 запросов к базе.

Оказывается что Views сначала выполняет все операции над полями для сортировки, а затем повторно эти же запросы для вывода.
Отключаем сортировку 900 запросов. (База не маленькая.)

Вижу единственный выход в передачи отсортированного списка nid'ов, (своя сортировка выполняется в 100 раз быстрее чем через views),
но тут проблема не вижу у Views возможности выводить ноды в порядке поступивших аргументов.

Чувствую что пропустил еще варианты решения проблемы но не могу достучаться до своего мозга )

graker
Аватар пользователя graker

Вот уж не знаю, как на такое ответить :)
Может, надо прямо php-скриптом результаты сортировать, перед выводом?

Гость (гость)
Аватар пользователя Гость

В шаблоне вывода views?

graker
Аватар пользователя graker

Ну я это имел в виду, да.

Гость (гость)
Аватар пользователя Гость

хммм, тут проблемка с paginate, все спокойно сортируется но на каждой странице отдельно )))
я так понимаю нужно отключить paginate у views и опять же сделать его вручную в шаблоне? ))

а есть ли встроенные drupal функции для paginate или придется ручками делать?

graker
Аватар пользователя graker

theme('pager'), наверное :)

Гость (гость)
Аватар пользователя Гость

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

graker
Аватар пользователя graker

В комментарии явно не хватает названия модуля :)

Гость (гость)
Аватар пользователя Гость

Есть два подобных модуля:
1. Views Argument Sort - в данный момент работает и быстро
2. Views Arguments Extras - помимо сортировки может делать что-то еще, но пока не работает =)

Оба еще в стадии разработки.

Андрей (гость)
Аватар пользователя Андрей

Интересно а как дело обстоит с VIEWS3 и Drupal7 ? Пробовал ли уже кто-то подключать свою таблицу в семерке? Есть ли отличия? также интересует, если например эта таблица создана как entity и потом к ней добавлены поля уже через админку, то эти поля будут отбражаться во вьювс, или их каким-то образом тоже надо будет подключать?

Буду благодарен за любые комментарии

bigferumdron (гость)
Аватар пользователя bigferumdron

Здравствуйте. Скажите, а реально ли в этом вычисляемом поле использовать условия на пхп, типо if else либо какие-то пхп функции?

graker
Аватар пользователя graker

Да.

bigferumdron (гость)
Аватар пользователя bigferumdron

Ваша статья реально служит хорошей опорой. Пишу хендлер под view3. Задача в сортировке, по вычисляемому значению. Суть вычислений проста. Поле в базе, в котором хранится время(UNIX формате) когда заканчивается срок действия VIP услуг на сайте. Если значение этого поля больше, чем возвращает функция time() в момент запроса вьюхи - значит это ВИП аккаунт, иначе - обычный. Так вот, мне нужно отсортировать ноды, чтобы сверху были вип , а ниже - обычные. Плюс ко всему при перезагрузке страницы, анкеты должны перемешиваться, но при этом все равно сверху вип, снизу обычные(именно из-за этого перемещивания стандартными средствами уже не решить). После прочтения вашего мануала решил пробовать сделать свой хендлер сортировщик, который будет сортировать по вип не вип на основании вычесленного значения.

Вот не совсем понимаю как действовать и нужно ли вобще использовать свой сортировщик. Понимаю, что мне понадобится сортировка по вычисляемому полю, следовательно нужно брать за основу хендлер с формулой. Но во views 3 - в папке хендлеров нет views_handler_sort_formula . Похоже за основу надо брать что-то другое?

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

bigferumdron (гость)
Аватар пользователя bigferumdron

Я дико извиняюсь за навязчивость, возможно прошлый комментарий был слишком глобальный. Вопрос лишь в том, как в DRUPAL7 и VIEWS 3 использовать формулы в handler сортировках. Это вообще реально? или там их нет...

graker
Аватар пользователя graker

Не, прошлый комментарий хороший.
Некоторые мысли.
1. Views сам умеет сортировать по полям, будь то datetime или timestamp (с которым можно работать как с числом).
2. Во Views есть сортировка по рандому — для перемешивания результатов.
3. Если первой пустить сортировку по датам, а второй — по рандому, наверное получится не очень хорошо, т.к. сортировщик перемешает записи только с одинаковой датой (т.е. практически никакие).
Но есть варианты:
а) выводить два вьюса — один главный, другой аттачем, сверху только випы, перемешанные, снизу — обычные, в остальных настройках оба вьюса одинаковы;
б) можно посмотреть вот сюда: http://drupal.org/project/views_php и попробовать написать код для пост-сортировки, когда вьюс уже выполнен (но это плохой вариант);
в) можно ввести тупое дополнительное поле в БД, определяющее «вип — не вип» (1 — 0) и сортировать по нему.
г) вообще с формулой, конечно, тоже неплохо, особенно если формула возвращает тупо 1 для випа и 0 для невипа, чтоб рандом работал. Формулу сделать, видимо, все же можно. Про views_handler_sort_formula написано тут:

views_handler_sort_formula has been removed.
Everyone who used it can extend from views_handler_sort, too.

Видимо, это значит, что свой хэндлер надо наследовать прямо от обычного handler_sort.

bigferumdron (гость)
Аватар пользователя bigferumdron

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

Получилось, благодаря Вам. Может не совсем верно, т.е. в друпал веи, но работает и похоже на правду. Т.е. задачей было реализовать такой хендлер сортировки, который возращал бы 1 если анкета ВИП (т.е. время указанное в соотв. поле больше чем текущее на момент просмотра) или 0 - если анкета обычная. Тогда можно было бы сделать во вьюхе 2 сортировки. Верхнюю - с помощью этого самого хендлера, а нижнюю - обычный рандомайз.

Что касается кастомного сортировщика:

1. В инфо файле зарегистрировал hook_views_api
2. В файле имя_модуля.views.inc реализовал hook_views_data (У меня имя модуля - custom_filter)

function custom_filter_views_data() {
      $data['node']['mycustomsort'] = array(
        'group' => t('Custom'),
        'title' => 'Сортировка вип не вип',
        'help' => t('My custom sort'),
        'sort' =>  array('handler' => 'custom_filter_handler_sort_mycustomsort'),
     
    );
    return $data;
 
}

3. Создал файл custom_filter_handler_sort_mycustomsort.inc внутри которого определил непосредственно хендлер

class custom_filter_handler_sort_mycustomsort extends views_handler_sort {
 
  function query() {
    $this->ensure_my_table();
    $join = new views_join();
    $join->construct('field_data_field_timevip', $this->table_alias, 'nid', 'entity_id',"field_data_field_timevip.entity_type = 'node' AND field_data_field_timevip.deleted = '0'");
    $this->query->ensure_table('field_data_field_timevip', $this->relationship, $join);
    $this->query->add_orderby(NULL, '(field_data_field_timevip.field_timevip_value >' . time() . ')', $this->options['order'], 'timevip_filter');  
  }
   
 }
}

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

Решил поделится, мало ли, кому будет полезно..

graker
Аватар пользователя graker

Ну почему не друпал-вей — самый что ни есть друпал-вей :)
Спасибо, что результатом поделились.

bigferumdron (гость)
Аватар пользователя bigferumdron

Graker поправь пожалуйста хендлер. Выслал по ошибке слегка некорректный вариант (метод add_orderby не совсем верно юзал)

function query() {
  $this->ensure_my_table();
  $join = new views_join();
  $join->construct('field_data_field_timevip', $this->table_alias, 'nid', 'entity_id',"field_data_field_timevip.entity_type = 'node' AND field_data_field_timevip.deleted = '0'");
  $this->query->ensure_table('field_data_field_timevip', $this->relationship, $join);
  $this->query->add_orderby(NULL, '(field_data_field_timevip.field_timevip_value >' . time() . ')', $this->options['order'], 'timevip_filter');  
}

graker
Аватар пользователя graker

Поправил :)

Роман (гость)
Аватар пользователя Роман

Большое спасибо за статью, очень интересно и полезно.

Скажите пожалуйста, а каким образом, к примеру, формировать с помощью Views запросы, в которых в аргументах присутствуют ">", "<", "BETWEEN" и т.д.

Например, чтобы передать вьюшке значения nid1 и nid2, а она выдала список нод, nid у которых находится в промежутке между nid1 и nid2.

В обычном SQL такое решается элементарно, а вот как это сделать во Views ?

У меня есть предположение, что нужно хэндлер унаследовать от views_handler_argument, но вот никак не могу найти пример для изучения.

graker
Аватар пользователя graker

Можно вот тут посмотреть, что люди делают: http://drupal.org/node/1417886

Роман (гость)
Аватар пользователя Роман

Добрый день.

Скажите пожалуйста, каким образом настраивать $data['testnode']['table']['join'], если своя таблица является связывающей таблицей между базовыми, либо задает взаимосвязь между отдельными элементами внутри одной и той же базовой таблицы ?

Например, я задаю свою таблицу, которая задает связь между нодами (дочерняя - родительская) и имеет такую структуру:
nid - ID текущей ноды
nid_parent - ID родительской ноды

Есть ли возможность задать через $data['testnode']['table']['join'] не одну, а две связки ?

Первая - через поле nid, чтобы получить доступ к родительским нодам.
А вторая - через поле nid_parent, чтобы получить доступ к дочерним нодам.

И можно ли в таком случае связь с родительскими или дочерними нодами оформить во views как одно отношение ? Например,при задании отношений можно выбрать "Содержимое: родительские узлы" или "Содержимое: дочерние узлы", и будет получен доступ к полям родительских или дочерних узлов.

graker
Аватар пользователя graker

Рилейшены надо использовать в описании хендлеров.
Сюда загляните: https://drupal.org/node/891986

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

CAPTCHA
Пройдите, пожалуйста, проверку. Она нужна, чтобы отличать людей от спам-роботов. А если не хотите проходить эту проверку регулярно — зарегистрируйтесь.
Image CAPTCHA
Введите цифры, изображенные на картинке (без пробелов).