Views3 y subconsultas?

12

Tengo una vista que genera una consulta que hace múltiples combinaciones. Esto produce una unión cartesiana, y necesito "convertir" las uniones en subconsultas.

He revisado la documentación, los resultados de búsqueda de Google y otras fuentes, pero no puedo encontrar ninguna descripción decente sobre cómo puedo configurar las Vistas para hacer subconsultas. He usado hook_views_data () para configurar las relaciones (que ahora se llevan a cabo como uniones). ¿De alguna manera es posible definir subconsultas a través de hook_views_data (), o necesito tomar otro enfoque?

Cualquier consejo apreciado!

sbrattla
fuente

Respuestas:

5

Miré más allá, pero realmente no pude encontrar ninguna documentación que describa esto.

Lo que necesitaba era una forma de unir la tabla de usuarios con otras dos tablas con datos para los usuarios. Sin embargo, las otras dos tablas están en una relación 'uno a muchos' con la tabla de usuarios, lo que significa que terminaré con una unión cartesiana si intento unirme a la tabla de usuarios con ambas tablas al mismo tiempo . Sin embargo, dado que todo lo que necesito es contar el número de registros en las otras dos tablas asociadas con un usuario determinado, una subconsulta debería poder hacer el truco. Sin embargo, no pude encontrar ninguna documentación sobre Vistas y subconsultas, así que esto es lo que hice.

  1. Creado dos campos ficticios

Creé dos campos ficticios (que llamaré 'descargas' y 'escuchas') a través de hook_views_data (). La definición del campo se enumera a continuación.

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

Ahora, cuando configure una vista para usuarios, aparecerán los campos 'Descargas' y 'Escuchas'. Sin embargo, intentar ejecutar una consulta ahora generará un error ya que los campos ficticios, después de todo, son campos ficticios. Ellos no existen. El único propósito de estos campos es indicarle a nuestra implementación de hook_views_query_alter () que necesita hacer unos pocos replacemenets.

  1. Implementar hook_views_query_alter ()

El truco aquí es verificar si la consulta dada incluye los campos 'Descargas' o 'Escuchas'. Si lo hace, eliminaremos los campos de la consulta y los reemplazaremos con subconsultas. La implementación de esta función es la siguiente.

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

Tenga en cuenta que estamos reutilizando el alias del campo eliminado para la subconsulta. De esa forma, Views pensará que el valor devuelto por la subconsulta en realidad proviene del campo ficticio (que, después de todo, no existe).

Esto es. No estamos obteniendo una unión cartesiana y tanto las 'descargas' como las 'escuchas' se cuentan correctamente.

sbrattla
fuente
4

Usé la solución de sbrattla hasta que necesité que la subconsulta heredara los valores del filtro. Ahora uso el módulo views_field_view para incrustar una vista separada que realiza la consulta de conteo. Puedo pasar valores de filtro de contexto a esa vista incrustada a través del módulo views_filterfield (que escribí) que hace que los valores de filtro estén disponibles como campos de vista (y, por lo tanto, tokens).

La consulta de recuento ahora funciona y hereda los filtros expuestos en la consulta principal.

Cafuego
fuente