Views3 e subconsultas?

12

Eu tenho uma visão que gera uma consulta que faz várias associações. Isso produz uma junção cartesiana e eu preciso "converter" as junções em subconsultas.

Examinei a documentação, os resultados de pesquisa do Google e outras fontes, mas não consigo encontrar uma descrição decente de como posso configurar o Views para fazer subconsultas. Eu usei hook_views_data () para configurar os relacionamentos (que agora são realizados como junções). De alguma forma, é possível definir subconsultas por meio de hook_views_data () ou preciso usar outra abordagem?

Qualquer conselho apreciado!

sbrattla
fonte

Respostas:

5

Eu olhei mais longe, mas não consegui encontrar nenhuma documentação descrevendo isso.

O que eu precisava era de uma maneira de ingressar na tabela de usuários com outras duas tabelas contendo dados para os usuários. No entanto, as outras duas tabelas estão em um relacionamento "um para muitos" com a tabela de usuários, o que significa que eu terminarei com uma junção cartesiana se tentar associar a tabela de usuários com essas duas tabelas ao mesmo tempo . No entanto, como tudo o que preciso é contar o número de registros nas duas outras tabelas associadas a um determinado usuário, uma subconsulta deve ser capaz de executar o truque. No entanto, não consegui encontrar nenhuma documentação sobre Views e subconsultas - então, aqui está o que eu fiz.

  1. Criou dois campos fictícios

Criei dois campos fictícios (que chamarei de 'downloads' e 'escuta') por meio de hook_views_data (). A definição do campo está listada abaixo.

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',
      ),
    )
  ),
);

Agora, quando você configura uma visualização para usuários, os campos 'Downloads' e 'Escuta' aparecerão. No entanto, tentar executar uma consulta agora resultará em um erro, pois os campos fictícios, afinal, são campos fictícios. Eles não existem. O único objetivo desses campos é sinalizar para nossa implementação de hook_views_query_alter () que ele precisa executar alguns substituintes.

  1. Implementar hook_views_query_alter ()

O truque aqui é verificar se a consulta fornecida inclui os campos 'Downloads' ou 'Escuta'. Nesse caso, removeremos os campos da consulta e os substituiremos por subconsultas. A implementação desta função é a seguinte.

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;
      }
    }
  }
}

Observe que estamos reutilizando o alias do campo removido para a subconsulta. Dessa forma, o Views pensará que o valor retornado da subconsulta realmente vem do campo fictício (que, afinal, não existe).

Isso é. Não estamos recebendo uma junção cartesiana e os downloads e as escutas são contados corretamente.

sbrattla
fonte
4

Usei a solução da sbrattla até precisar que a subconsulta herdasse os valores do filtro. Agora eu uso o módulo views_field_view para incorporar uma exibição separada que executa a consulta de contagem. Posso passar valores de filtro de contexto para essa exibição incorporada por meio do módulo views_filterfield (que escrevi) que disponibiliza valores de filtro como campos de exibição (e, portanto, tokens).

A consulta de contagem agora funciona e herda os filtros expostos na consulta principal.

Cafuego
fonte