Views3 и подзапросы?

12

У меня есть представление, которое генерирует запрос, который делает несколько соединений. Это приводит к декартовому объединению, и мне нужно «преобразовать» объединения в подзапросы.

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

Любой совет приветствуется!

sbrattla
источник

Ответы:

5

Я посмотрел дальше, но не смог найти никакой документации, описывающей это.

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

  1. Создано два фиктивных поля

Я создал два фиктивных поля (которые я назову «downloads» и «listens») с помощью hook_views_data (). Определение поля приведено ниже.

function hook_views_data() {

  $data['users'] = array(
    'downloads' => array(
      'title' => t('Downloads'),
      'field' => array(
        'handler' => 'views_handler_field_numeric',
        'click sortable' => TRUE,
      ),
      'filter' => array(
        'handler' => 'views_handler_filter_numeric',
      ),
      'sort' => array(
        'handler' => 'views_handler_sort',
      ),
    ),
    'listens' => array(
      'title' => t('Listens'),
      'field' => array(
        'handler' => 'views_handler_field_numeric',
        'click sortable' => TRUE,
      ),
      'filter' => array(
        'handler' => 'views_handler_filter_numeric',
      ),
      'sort' => array(
        'handler' => 'views_handler_sort',
      ),
    )
  ),
);

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

  1. Реализуйте hook_views_query_alter ()

Хитрость заключается в том, чтобы проверить, включает ли данный запрос поля «Загрузки» или «Прослушивает». Если это произойдет, мы удалим поля из запроса и заменим их подзапросами. Реализация этой функции идет следующим образом.

function mta_views_query_alter(&$view, &$query) {

  foreach ($query->fields as $field_key => &$field_values) {
    if ($field_values['table'] == 'users') {

      switch ($field_values['field']) {
        case 'downloads':
          unset($query->fields[$field_key]);
          $query->add_field(null, "(SELECT COUNT(*) FROM {fileusage} fu WHERE fu.externaluser = {users}.uid AND fu.action = 0)", $field_key);
          break;
        case 'listens':
          unset($query->fields[$field_key]);
          $query->add_field(null, "(SELECT COUNT(*) FROM {fileusage} fu WHERE fu.externaluser = {users}.uid AND fu.action = 1)", $field_key);
          break;
      }
    }
  }
}

Обратите внимание, что мы повторно используем псевдоним удаленного поля для подзапроса. Таким образом, Views будет думать, что значение, возвращаемое из подзапроса, на самом деле происходит из фиктивного поля (которое в конце концов не существует).

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

sbrattla
источник
4

Я использовал решение sbrattla до тех пор, пока мне не понадобилось наследовать значения фильтра подзапроса. Теперь я использую модуль views_field_view для встраивания отдельного представления, которое выполняет запрос подсчета. Я могу передать значения фильтра контекста этому встроенному представлению через модуль views_filterfield (который я написал), который делает значения фильтра доступными как поля представления (и, следовательно, токены).

Запрос количества теперь работает и наследует открытые фильтры основного запроса.

Cafuego
источник