Vues3 et sous-requêtes?

12

J'ai une vue qui génère une requête qui effectue plusieurs jointures. Cela produit une jointure cartésienne, et j'ai besoin de "convertir" les jointures en sous-requêtes.

J'ai parcouru la documentation, les résultats de recherche Google et d'autres sources, mais je ne trouve aucune description décente de la façon dont je peux configurer Views pour effectuer des sous-requêtes. J'ai utilisé hook_views_data () pour configurer les relations (qui sont maintenant effectuées en tant que jointures). Est-il possible de définir des sous-requêtes via hook_views_data (), ou dois-je adopter une autre approche?

Tout conseil apprécié!

sbrattla
la source

Réponses:

5

J'ai regardé plus loin, mais je n'ai pas vraiment trouvé de documentation décrivant cela.

Ce dont j'avais besoin était un moyen de joindre la table des utilisateurs à deux autres tables contenant des données pour les utilisateurs. Cependant, les deux autres tables sont dans une relation «un-à-plusieurs» avec la table des utilisateurs, ce qui signifie que je vais me retrouver avec une jointure cartésienne si j'essaye de joindre la table des utilisateurs avec ces deux tables en même temps . Cependant, comme tout ce dont j'ai besoin est de compter le nombre d'enregistrements dans les deux autres tables associées à un utilisateur donné, une sous-requête devrait être en mesure de faire l'affaire. Cependant, je n'ai trouvé aucune documentation sur les vues et les sous-requêtes - voici donc ce que j'ai fait.

  1. Création de deux champs fictifs

J'ai créé deux champs fictifs (que j'appellerai «téléchargements» et «écoute») via hook_views_data (). La définition du champ est indiquée ci-dessous.

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

Maintenant, lorsque vous configurez une vue pour les utilisateurs, les champs «Téléchargements» et «Écoute» apparaissent. Cependant, tenter d'exécuter une requête maintenant entraînera une erreur car les champs fictifs sont tous des champs fictifs. Ils n'existent pas. Le seul but de ces champs est de signaler à notre implémentation de hook_views_query_alter () qu'il a besoin de faire quelques replacemenets.

  1. Implémentez hook_views_query_alter ()

L'astuce consiste à vérifier si la requête donnée inclut les champs «Téléchargements» ou «Écoute». Si c'est le cas, nous supprimerons les champs de la requête et les remplacerons par des sous-requêtes. L'implémentation de cette fonction se déroule comme ci-dessous.

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

Notez que nous réutilisons l'alias du champ supprimé pour la sous-requête. De cette façon, Views pensera que la valeur renvoyée par la sous-requête provient en fait du champ fictif (qui, après tout, n'existe pas).

C'est. Nous n'obtenons pas de jointure cartésienne et les «téléchargements» et les «écoutes» sont comptés correctement.

sbrattla
la source
4

J'ai utilisé la solution de sbrattla jusqu'à ce que j'aie besoin que la sous-requête hérite des valeurs de filtre. J'utilise maintenant le module views_field_view pour incorporer une vue distincte qui effectue la requête de comptage. Je peux transmettre des valeurs de filtre de contexte à cette vue intégrée via le module views_filterfield (que j'ai écrit) qui rend les valeurs de filtre disponibles sous forme de champs de vue (et donc de jetons).

La requête de comptage fonctionne maintenant et hérite des filtres exposés sur la requête principale.

Cafuego
la source