web-dev-qa-db-fra.com

Pourquoi `GROUP BY` dans hook_views_query_alter () ne fonctionne pas?

J'utilise Views 7.x-3.6 et j'ai essayé de modifier la clause GROUP BY Avec hook_views_query_alter() comme ci-dessous:

function mymodule_views_query_alter(&$view, &$query) {
    if ($view->name == "view_name"){
      $query->add_groupby('field_name');
      dpm($query);    
    }
}

Quand je regarde dans $query, la clause groupby est correctement activée mais la requête SQL n'est pas affectée : la clause GROUP BY n'apparaît pas:

enter image description here

J'ai finalement utilisé un Drupal core hook ( hook_query_alter() ) et cela a bien fonctionné: le SQL est maintenant affecté.

function mymodule_query_alter(QueryAlterableInterface $query) {
  $view_name = 'view_name';
  if ($query->hasTag('views_' . $view_name)) {    
    $query->groupBy('field_name');
  }
}

Une raison pour laquelle mon hook_views_query_alter() ne fonctionne pas? Je me demande s'il y a une façon plus propre de le faire et.

11
jozi

Utilisez add_field() avec le paramètre array('function' => 'groupby').

$query->add_field('node', 'nid', 'node_nid', array('function' => 'groupby'));
$query->add_groupby('node.nid');

Informations supplémentaires:

Après avoir utilisé add_groupby vous pourriez voir le code suivant après GROUP BY:

GROUP BY node.nid, nid

Voir le prochain numéro: https://drupal.org/node/1578808

Pour éviter les conditions GROUP BY inutiles, ajoutez:

$query->distinct = TRUE;
11
milkovsky

Si vous rencontrez toujours des instructions GROUP BY inutiles ajoutées à la requête, vous pouvez les supprimer dans hook_query_alter(). J'ai résolu le problème de la commande des commentaires par la plupart des commentaires des parents commentés par exemple.

Donc dans hook_views_query_alter() j'ai:

/**
 * Implements hook_views_query_alter().
 */
function MODULENAME_views_query_alter(&$view, &$query) {
  if ($view->name == 'reviews' && $query->orderby[0]['field'] == 'comment_thread') {
    $join = new views_join;
    $join->construct('comment', 'comment', 'cid', 'pid', NULL, 'LEFT');
    $query->add_relationship('c1', $join, 'comment');
    $query->add_field('comment', 'pid', 'c1_pid', array('function' => 'groupby'));
    $query->add_groupby('c1.pid');
    $query->add_orderby(NULL, 'COUNT(c1.cid)', 'DESC', 'comments_count');
    $query->distinct = TRUE;
    $query->orderby[0] = $query->orderby[count($query->orderby) - 1];
    unset($query->orderby[count($query->orderby) - 1]);
  }
}

J'ai une erreur liée à l'impossibilité de regrouper par

comments_count

champ qui est en fait le résultat de la fonction SQL COUNT().

Je me suis retrouvé avec ceci:

/**
 * Implements hook_query_alter().
 */
function MODULENAME_query_alter(QueryAlterableInterface $query) {
  if (isset($query->alterMetaData['view']->name) && $query->alterMetaData['view']->name == 'reviews') {
    $fields =& $query->getGroupBy();
    foreach (array_keys($fields) as $key) {
      // Remove group by statements from generated query which were actually not set in view query.
      if (!in_array($key, $query->alterMetaData['view']->query->groupby)) {
        unset($fields[$key]);
      }
    }
  }
}
1
Dmitriy

Tard dans la soirée mais cela pourrait aider quelqu'un d'autre.

Dans mon cas, je fournissais une liste d'utilisateurs (à l'aide du module supplémentaire Profile2) avec un champ Taxonomy Term ( https://drupal.org/node/180832 ). Je voyais plusieurs résultats dont je ne pouvais pas me débarrasser via l'API Views 3.

Dans mon module personnalisé, j'ai ajouté:

/**
    Implementation of hook_views_query_alter()
**/
function MYMODULE_views_query_alter(&$view, &$query) {

  if($view->name == "provider_results_list" && $view->current_display == "page_1") {

    $query->distinct = TRUE;

    // User the provider uid to make the results distinct: using a taxonomy field for
    // keyword searches brings up multiple results. 
    $query->add_field('profile', 'uid', 'provider_uid', array('function' => 'groupby'));

  }
}

Les paramètres pour add_field sont

add_field(TABLE_NAME, FIELD, FIELD_ALIAS, array('function' => 'groupby'))
1
appaulmac

En Drupal 8 et grâce à l'approche graceman9, ce sera:

use Drupal\Core\Database\Query\AlterableInterface;

function MYMODULE_query_alter(AlterableInterface $query) {
  if (isset($query->alterMetaData['view'])) {
    if($query->alterMetaData['view']->id() == 'replace_by_view_machine_name') {
      // Group by UID to remove duplicates from View results
      $query->groupBy('users_field_data.uid');
      // If multilingual site, you should add the following
      // $query->groupBy('users_field_data.langcode');
    }
  }
}
0
romain ni

Je me suis demandé que personne ne fournissait une vraie solution qui fonctionne. Il y a une telle méthode que j'ai trouvée ici , merci beaucoup à @ b-ravanbakhsh:

/**
 * Implements hook_query_alter().
 */
function MODULENAME_query_alter(QueryAlterableInterface $query) {
  if (isset($query->alterMetaData['view'])) {
    if($query->alterMetaData['view']->name == 'YOUR_VIEW_NAME'){
      // also you can unset other group by critera by using, unset($query->getGroupBy());
      $query->groupBy('users.uid');
    }
  }
}
0
graceman9

C'est ainsi que cela se fait dans views_query_alter; la partie node_access n'est pas nécessaire.

function xdas_target_audience_views_query_alter(&$view, &$query) {
  $controlled_views = variable_get('xdas_target_audience_views', array(
    'landing_products',
    'promotions',
    'landing_coupons',
    'landing_coupons_belvita',
    'landing_coupons_lulu',
    'related_coupon',
    'cuponazo',
    'banner',
    'brands',
  ));
  if (in_array($view->name, $controlled_views) && $view->base_table == 'node') {
    //add node_access to views so we can control access.
    $query->add_tag('node_access');
    $join = new views_join();
    $join->construct('xdas_target_audience_boost', 'node', 'nid', 'nid');        
    $query->add_relationship('xdas_target_audience_boost', $join, 'node');
    $query->add_field('xdas_target_audience_boost', 'score', 'score' , array('function' => 'max'));
    $query->add_orderby(NULL, NULL, 'DESC', 'score');   
    $query->add_groupby('nid');    
  }
}

Si vous regardez la documentation de hook_views_query_alter , je pense que la requête est déjà prête à s'exécuter. Par exemple, des remplacements ont été effectués par l'API de base de données et sont sur le point d'être envoyés par câble à MySQL. Un autre n exemple d'utilisation de hook_views_query_alter peut être vu sur le blog BTMash .

Cela étant, vous n'avez plus d'objet de requête DB, mais les éléments de l'instruction SQL avec des expressions, des variables, etc. sous forme de tableau.

Je n'ai pas de requête devant moi mais quelque chose comme le code non testé suivant est ce que vous voulez:

$query->groupby[0]['field'] = 'field_name';
0
tenken