修改 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)。這並不是我們想要的,但沒關係,因為即將下來透過程式碼進行修改。

 

此時,如果你有打開 SQL 預覽,可以對比增加 Filter Criteria 前後的 SQL 變化。沒錯,會寫程式的你應看懂 Views 是在做什麼..
([admin/structure/views/settings] -> Live preview settings ->  Show the SQL query)


Views 將一個資料庫表關連了,並設定了 WHERE 過濾條件。所以,我們最終要改變的將是 WHERE 條件中的 IN('Drupal Team') 為當前使用者的 Team

hook_views_query_alter() 真正登場了

*** 下面程式碼包含了詳細註釋,由上至下細看***
(dpm 是 Drupal Devel 模組的 Debug Function)


/**
 * 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,重新整理網頁,應有其效果了!

( 到此為止,要是看不懂,猜想還沒達到 PHP 基本水平。好好再學學 PHP 。 )

 

上面 [K-1] 處的 我們使用了 FOREACH 語句。只要你掌握到所需的資料表,你還可以取消 Filter Criteria: User: Team (= Drupal Team),及將該處程式碼替代為:


// 增加上面關聯的資料表
    $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');

 

除了註釋,實際只有十行左右。附上測試模組。

扔掉你的 Jump Menu 模組,用 Views 3 打造跳轉選單

寫 Drupal 的東西比較麻煩,小小的功能可能要長篇大論及涉及太多模組。今天這篇例外,簡約三分鐘分享:

要造一個如下的跳轉選單,可以用各式模組或自個兒寫 Javascripts 來完成,不過有了 Views 3 就變得更簡單

我相信聰明的大家,純粹通過看圖也懂 (廢話不多說了):

圖中(Views 3 的設定介面) 的 Content: Address 3 & 4 正是第一張圖片的內容,可很靈活應用。

** 如果你的 Drupal 安裝在子資料夾中,要打這個 PATCH: http://drupal.org/node/1227302

Views 模組:自定一個按月彙整日期收合或展開日期列表功能

Views 內置了一個 Archives Default Views,但不能滿足需求。就像這位朋友需要一個 "按月彙整日期收合或展開日期列表功能"

有模組做嗎 ?? 不知。不過使用 Views 加上少許的 jQuery 還是能輕鬆達到效果,不花你十分鐘的時間。(** 文章最後附有 Views 2 Export Code)

首先看看 "月彙整日期收合或展開日期列表" 需要什麼:

  • 按年份及月份區分
  • 每一個 "年份及月份" 下列出該月份每天的文章
  • 列出的文章包括了發表日期及標題連結

好了,我們簡單地建立一個 Views, 做一些很基本的設定,取出必要的 Fields。

由於我們要按年月份區分,所以 Node: Post date 需要自定日期格式:

其一個是: Y M
另一個是:d

唯一必要注意的是:我們要以年月日期來作群組:

假如你沒有設定錯誤,會看到相似的列表:

已經接近成功了!! 接下來是一些 CSS 及 jQuery Code

CSS 隨你喜歡了,我給了個參考:


.view-MonthlyArchives .views-field-created-1,
.view-MonthlyArchives .views-field-title { float:left; margin-right:10px}

.view-MonthlyArchives .view-content li,
.view-MonthlyArchives .view-content .item-list
 {clear:both}

jQuery Code:


$(document).ready(function(){
				
				var vMA = $('.view-MonthlyArchives').find('.view-content');
				$(vMA).find('ul').hide();
				
				 $(vMA).find('ul').each(function(){
					var li_count = $(this).find('li').length;
					$(this).prev('h3').append(' (' + li_count + ')');
					});

				$(vMA).find('h3').click(function() {
					$(this).next('ul').slideToggle('fast');
				});

			});

注意:.view-MonthlyAcrchives 是來自 Views 名稱的,你需要修改為正確的。

怎麼增加 jQuery Code ??

最簡單當然是直接貼在版型中啦。也可以另存新檔,在版型 .info 中增加:

scripts[] = scripts.js // 你的檔案名,然後再清除 CACHES 才有效果哦 !!
 

就是這麼簡單,最終效果:

假如你沒能做到,直接匯入 Views Export Code 看看。