欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

​修改Drupal Views SQL 没难度! 有大用

修改Drupal Views SQL 没难度![hook_views_query_alter]     

Drupal Views让你可透过界面设定所需条件,轻松抓取特定资料。不过开发者创意无限,Views架构没可能完全满足您的要求。在此时,可以考虑使用hook_views_query_alter()修改/增强Views预设不能满足的条件。        

引用Drupal Taiwan论坛上一问题作例子:        

做出一个列表,当使用者登入后,可以看到同一组别的成员            

对于Views,这类列表本是很简单,但要实现时却发现问题:Views 只能过滤登入使用者的ID (User: Current)。要以登入使用者的角色或其他因素似乎有点难度。        

在主题中,我提出了使用Contextual的方案,问题的确能解决,但你的URL将变成:my-group-member/{使用者的组别}。也不太完美。(另外,也提及了Views PHP,估计也能达成效果,但笔者想更深入地看看万能的方法)        

不能确认原发问者需求,为此教程,笔者定义组员列表规格        

  • 列表中只能看到同一组别的成员(此教学中,我们将要列出K Team 成员)

  • URL:example.com/ my-group-member

  • 透过Profile增加一个Team ( field_team )选择栏位,包括选项:K Team | Drupal Team

修改Views Query        

在此略过写模组的基本需要。我们来建立一个View,然后如下图设置。(为了说的更清晰,笔者去除了多余的设定) 
我们增加了User: Team (= Drupal Team)。这并不是我们想要的,但没关系,因为即将下来透过程式码进行修改。 

image.png




此时,如果你有打开SQL预览,可以对比增加Filter Criteria前后的SQL变化。没错,会写程式的你应看懂Views是在做什么.. 
[admin/structure/views/settings] -> Live preview settings -> Show the SQL query)        

image.png



Views将一个资料库表关连了,并设定了WHERE过滤条件。所以,我们最终要改变的将是WHERE条件中的IN('Drupal Team')为当前使用者的Team        

hook_views_query_alter() 真正登场了        

***下面程式码包含了详细注释,由上至下细看***
(dpm是Drupal Devel模组的Debug Function )        

PHP            
/**
 * hook_views_query_alter
 * 模組名_views_query_alter
 */
function alterquery_views_query_alter(&$view, &$query) {
  // 看看有什麼東西
  dpm($view, 'Views 的所有資訊');
  dpm($query, 'Views SQL 查詢');

  if (
    // Views 的 Machine Name
    $view->name == 'my_group_member' 
    // Views 頁面 Machine Name (收藏在設定頁面的 Advanced 裏)
    && $view->current_display == 'page' 
  )
  {
    if(!isset($user)) { // $user 是保存當前使用者資訊的變數。在這裏我們檢查有否載入
      $user = user_load($GLOBALS['user']->uid);
    }
    dpm($user, '當前使用者資訊');

    /**
     * $user_team = $user->field_team['und'][0]['value'];
     * 上面這行較直接,但之前談過,由於 Drupal 是支援多語言,這不是最好的方法。
     * 看:https://notabluescreen.com/field_get_items
     */
    $team = field_get_items('user', $user, 'field_team');
    $user_team = $team[0]['value'];
    dpm($team, '使用者組別資訊');


    /**
     * [K-1]我們需要修改 field_data_field_team.field_team_value 這一項
     */
    foreach ($query->where['1']['conditions'] as $key => $value) {
      if ($query->where['1']['conditions'][$key]['field'] == 'field_data_field_team.field_team_value') {
         $query->where['1']['conditions'][$key]['value'][0] = $user_team;
         break;
      }
    }

    // 看看有沒有正確修改
    dpm($query, '修改後的Views SQL 查詢');
  }
}



清除Drupal Caches,重新整理网页,应有其效果了!


image.png


(到此为止,要是看不懂,猜想还没达到PHP基本水平。好好再学学PHP 。 )        

 

上面[K-1]处的我们使用了FOREACH语句。只要你掌握到所需的资料表,你还可以取消Filter Criteria: User: Team (= Drupal Team),及将该处程式码替代为:        

PHP  




// 增加上面關聯的資料表
    $query->add_table('field_data_field_team');
    
    // 增加 WHERE 條件 (不難看出吧!跟上面 [K-1] 的程式碼是對應的)
    $query->add_where(0, 'field_data_field_team.field_team_value', array($user_team), 'in');




除了注释,实际只有十行左右。附上测试模组。


作者Kay.L标签 , , , , ,


“修改Drupal Views SQL 没难度![hook_views_query_alter]” 有8 则回响    

  1. ALOHA表示:                    

    HI,谢谢你还特别写了这篇文章!
    现在已经可以成功列出同一个群组的使用者了!                    

    但我有一个小小的问题@@~ 
    我的如果筛选的话是这个样子
    WHERE (( (field_data_field_unit_select.field_unit_select_tid = '6') ))                    

    我也有修改了一下您附上的测试模组
    $query->add_where(0, 'field_data_field_unit_select.field_unit_select_tid', array($user_unit), 'in');                    

    想问,最后那个in,是什么意思?                    

    因为我看到你附上的是IN ('Drupal Team') 
    而我的因为是下拉选单,所以是数字然后是”=” 
    可是没有特别修改,也可以列出同个单位的人耶!    


如果是IN('Drupal Team', 'Kay Team'),即为包含'Drupal Team' 及'Kay Team' 的意思。所以只有一个IN('6'),就等同于= '6'。可以Google “mySQL IN OR mySQL WHERE IN OR SQL IN” 看看相关教学                

IN部分是Comparison Operators (比较运算子),应能接受以下所有:
http://dev.mysql.com/doc/refman/5.5/en/comparison-operators.html          


喔喔ˊ~ 
了解了!! 
谢谢你的解说^^   


您好,我想请问hook_views_query_alter() 这个函数该要怎么使用?                    

我的情况是有一份由Webform产生,再建立的View资料表。
系统预设是捞出所有DATA,我想仅显示当前登入使用者的资料;但是系统的FILTER CRITERIA条件没有这条件,所以目前想透过SQL方式修改WHERE条件看能否可行。                    

但是hook_views_query_alter的说明文件第一行我就看不懂了Q_Q 
(不知该怎么确定那个MODULENAME(随意自订吗?),及该放入哪个资料夹,跟该从哪个路径可以执行/触发它)                    

恳请指导              


您好,抱歉回覆晚了。
有User:Current这个条件,但是没有效果,SQL的指令如下                        

SELECT webform_submissions.sid AS sid, webform_views.name AS webform_views_name, webform_views._date AS webform_views__date, webform_submissions.nid AS webform_submissions_nid, webform_submissions.uid AS webform_submissions_uid, node.uid AS node_uid, webform_views.sid AS webform_views_sid 
FROM 
{webform_submissions} webform_submissions 
LEFT JOIN { webform_views} webform_views ON webform_submissions.sid = webform_views.sid 
LEFT JOIN {webform_submissions} webform_submissions_webform_views ON webform_views.sid = webform_submissions_webform_views.sid 
LEFT JOIN {node} node ON webform_submissions.nid = node.nid 
LEFT JOIN {users} users_node ON node.uid = users_node.uid 
WHERE (users_node.uid = '1')                        

我的View是照论坛上的文章做成的。   




华生,我发现盲点了!                        

原来是我Relationship设错了,原先我设为[Webform views : Sid] 改为[Webform submissions: 使用者]后,就可以使用[User: Current]等条件来过滤为当前使用者。                        

终于解决啦,非常感谢QAQ   



“我想仅显示当前登入使用者的资料;但是系统的FILTER CRITERIA条件没有这条件”                        

“User: Current” 没有吗? 你仔细看看      

请教如何显示用户的各种类型的内容?每个用户一行,每个类型显示两个field。
实际上每个用户的每个内容类型最多一个node。                    

研究views join没成功。因为内容在相同的table里。






来自  https://notabluescreen.com/hook_views_query_alter/


普通分类: