Wednesday, November 09, 2011

How to use hook_query_alter() to alter Views in Drupal 7

Sometimes you need to alter a Views query by using the regular SelectQueryInterface methods without having to use the Views data structure in hook_views_query_alter(). It may get tedious at times working out all the views relationships, and arguments separately and adding a simple 'groupby' may get tricky if you do not have aggregation set in the view. It could also be that your hook_views_query_alter() runs a little too early for the $query to be modified.

Luckily, when the Views query is built in views_plugin_query_default::query a unique tag is added to each view of the form 'view_<view_name>':

// Go ahead and build the query. 
// db_select doesn't support to specify the key, so use getConnection directly.
$query = Database::getConnection($target, $key) 
  ->select($this->base_table, $this->base_table, $options) 
  ->addTag('views')
  ->addTag('views_' . $this->view->name);

Note: views_plugin_query_default::execute adds access data to the query which should be used for building access rights to the query during execution.

So, in your hook_query_alter(), you could identify the view based on its tag and modify the query like any other SelectQuery. I found this easier than using hook_views_query_alter() many times.

Example to group by a specific field: 

function hook_query_alter(QueryAlterableInterface $query){
  if ($query->hasTag('view_my_custom_view')) {
    $query->groupBy('n.type');
  }
}

No comments: