選單的使用 Menu System

1 篇文章 / 0 new
author
選單的使用 Menu System
選單的建立則須實作 hook_menu() , 說明如下 (當選單內容異動後, 須 清除系統快取 一次)
常用類型為
MENU_CALLBACK: 建立 URL 的請求路徑模式, 通常不會自動出現在系統選單內.
MENU_NORMAL_ITEM: 該模式選單會自動呈現在 系統的導覽 選單區塊內.
// Implementation of hook_menu()
function menufun_menu() {
    $items['menufun'] = array( // example.com/menufun, Key 則為URL的請求路徑
        'title' => 'Greeting',
        'page callback' => 'menufun_hello', //呼叫 function menufun_hello
        //'page arguments' => array('參數1', 3), //$para1 = '參數1', $para2 = path第三位置的內容
        //'page arguments' => array(1),
                 //若指定的參數個數沒有填滿function 參數的數目, 當path還有參數可取得時系統會在自動傳入
        'access callback' => TRUE, //選單權限管控 Defaults to user_access()
        'type' => MENU_CALLBACK,
        //'file' => 'menufun_greeting.inc', //告訴系統 function 所在的檔案
    );
    $items['menufun1'] = array(
        'title' => 'Navigation-Menu', //選單顯示標題
        'page callback' => 'menufun_hello',
        'access callback' => TRUE,
        'type' => MENU_NORMAL_ITEM, //直接出現在導覽選單內
    );
    $items['menufun1/child'] = array( // 子選單模式, parentKey/childKey
        'title' => 'Menu-child',
        'page callback' => 'menufun_hello',
        'access callback' => TRUE,
        'type' => MENU_NORMAL_ITEM,
    );
    return $items;
}
 
/**  Page callback.
 * example.com/menufun => $para1 = '', $para2 = ''
 * example.com/menufun/p1 => $para1 = 'p1', $para2 = ''
 * example.com/menufun/p1/p2 => $para1 = 'p1', $para2 = 'p2'
 * example.com/menufun/p1/p2/p3 => $para1 = 'p1', $para2 = 'p2' p3 無用
 * 設定 'page arguments' => array('固定', 1) => example.com/menufun/p1/p2 => $para1 = '固定', $para2 = 'p1'
 */
function menufun_hello($para1 = '', $para2 = '') {
    return t('Hello @para1 @para2', array('@para1' => $para1, '@para2' => $para2));
}

權限管控參數 access callback
function menufun_menu() {
...
    $items['menufun1/child'] = array(// 子選單模式, parentKey/childKey
        'title' => 'Menu-child',
        'page callback' => 'menufun_hello',
        //'access callback' => 'user_access', //告訴系統透過 function user_access() 來進行權限檢驗, 此為預設
        'access arguments' => array('receive greeting'), //許可權限項目
        'type' => MENU_NORMAL_ITEM,
    );
    return $items;
}
/**
 * Implementation of hook_permission()
 * 權限的檢查機制一般透過 user_access() 進行, 傳回 TRUE 則表示具有權限
 */
function menufun_permission() {
    return array(
        'receive greeting' => array( // 定義權限項目
            'title' => t('Receive a greeting'),
            'description' => t('Allow users receive a greeting message'),
        ),
    );
}

動態/多語系選單名稱 (選單參數 titles 或 descriptions 不要使用 t() )
要達成動態或多語系的選單名稱, 正確的方式是使用 'title callback' 參數, 藉由呼叫 function 來進行. 而 description 系統本就會自動進行t()的轉換程序.
function menufun_menu() {
...
    $items['menufun1/child'] = array(
        'title' => 'Menu-child',
        'title callback' => 'menufun_title', //call function 來產生選單標題
        'page callback' => 'menufun_hello',
        'type' => MENU_NORMAL_ITEM,
    );
    return $items;
}
// Title callback
function menufun_title() {
    drupal_set_title(t('The page title'));//指定標題內容, 一般頁面標題內容通常為選單 title 內容
    $now = format_date(time());
    return t('It is now @time', array('@time' => $now));
}

萬用字元 % 的運用
選單 % 的解析, URL的path 符合越完整則系統會觸發該項選單
$items['menufun'] << example.com/menufun 無%
$items['menufun/%'] << example.com/menufun/p1 表示至少須有一個參數, 符合則觸發此選單的 callback
$items['menufun/%/bb/%'] << example.com/menufun/p1/bb/p3 至少須有三個參數, 但第二個須為 bb
URL 的參數 index, 如 example.com/menufun/p1/p2/p3/p4, 則參數0:menufun, 參數1:p1, 參數2:p2, 參數3:p3, 參數4:p4, 這順序規則是固定不變, 所以選單中使用 'page arguments' => array(1, 3), 則callback時指定傳入的第一個參數是p1, 第二個參數是p3.

注意 : 當有使用萬用字元, 而指定的 callback 有需要傳入path內參數時最好使用 'page arguments' => array() 來指定要帶入哪些參數, 否則會會因$items['KEY-Path'] 中 KEY-Path 的內容不同, 傳入的第一個參數位置也有所不同, 如
$items['menufun/%/%']  若無指定 page arguments 時,
當 example.com/menufun/p1/p2/p3/p4 請求時傳入的第一個參數為 p3 而不是 p1,
也就是說無指定 page arguments 時, 傳入的第一個參數為扣除 KEY-Path 內容後的第一個位置為第一個參數.
而使用 'page arguments' => array(1, 2) array內指定的index順序不會因為KEY內容而有所變化, 1則為 p1, 2則為p2.

名稱式萬用字元 %NAME 的運用
若選單 KEY-Path 設定如 $items['menufun/%name/%'] 的方式, 除 % 外還後接英文字母, 則雖 %name 仍是為一個萬用字元%同樣效用外, 系統會自動呼叫 %NAME_to_arg($arg, $map, $index) 與 %NAME_load($arg, $map, $index) 這兩個函式.
function menufun_menu() {
...
    $items['menufun/aa/%para_name'] = array(//使用 %name 萬用字元, 須配合 _to_arg()或 _load() 此選單才會有效
        'title' => 'Greeting3',
        'load arguments' => array(2), // call function %PARA-NAME_load 時額外要傳入的參數
        'page callback' => 'menufun_hello', //呼叫 function menufun_hello
        'page arguments' => array(1),// example.com/menufun/a/b/c 則傳入參數為 a, c兩個, a為array(1)指定, c 為系統傳入
        'access callback' => TRUE,
        'type' => MENU_CALLBACK,
    );
    return $items;
}
 
//$arg : URL path %para_name 位置的參數內容, 系統固定自動傳入.
//$index : 指出 $arg 內容位於 URL path 參數的位置, 也等同  $map 參數陣列位置, 此例 %index=2
//$map : 將 URL path 參數項目以陣列形式傳入.(e.g. array('node','123','edit') for 'node/123/edit')
//需使用 $map, $index 參數內容, 將函式宣告成 para_name_to_arg($arg, $map, $index) 形式,系統自動傳入
 
function para_name_to_arg($arg) { //主要發生在系統要產生選單連結時會呼叫
    //return empty($arg) || $arg == '%' ? $GLOBALS['user']->uid : $arg;
    return 'arg'; //提供 %para_name 內容,除讓系統可以自動產生導覽選單項目外,亦可動態變換內容
}
 
//僅$arg系統會傳入內容同 _to_arg(), 需額外傳入參數則由 load arguments 設定
//特殊指定參數 'load arguments' => array('%map', '%index'),
// function para_name_load($arg, $map, $index), 則 $map, $index 內容同 _to_arg()
 
function para_name_load($arg) { //選單被調用時系統會呼叫並可將路徑參數傳入
    //資料處理
}
呼叫順序 _load()_to_arg()_load() , _load() 被呼叫兩次為何如此??? 尚須再研究
注意 : 使用名稱式萬用字元至少必須存在 _to_arg() 或 _load() 其中一個函式, 否則該選單永遠不會有效

變更其他模組的選單參數
/**
 * Implementation of hook_menu_alter(). 變更其他模組選單參數資料
 * @param array $items
 * Menu items keyed by path.
 */
function menufun_menu_alter(&$items) {
    // 變更 'user_logout' callback 到自己的 callback.
    $items['logout']['page callback'] = 'menufun_user_logout';
    // 原始 callback 的 function 是指向 user.pages.inc 內搜索
    unset($items['logout']['file']);
}
function menufun_user_logout() {
    global $user;
    watchdog('menufun', 'Session closed for %name.', array('%name' => $user->name));
}
變更前 logout 選單資料內容
array(
    'file' => 'user.pages.inc',
    'module' => 'user',
    'page callback' => 'user_logout',
...
變更後 logout 選單資料內容
array(
    'module' => 'user',
    'page callback' => 'menufun_user_logout',
...
 
變更選單連結資料
/**
 * Implements hook_menu_link_alter(). 選單連結資料儲存前可藉此更動
 * @param $item Associative array defining a menu link as passed into menu_link_save()
 */
function menufun_menu_link_alter(&$item) {
    if ($item['link_path'] == 'user/logout') {
        $item['link_title'] = 'Sign off';
    }
}
問題 : 當有多個模組都去更動同一個選單時(hook_menu_alter, hook_menu_link_alter), 那優先順序是如何決定?

頁面內選單
function milkshake_menu() {
    $items['milkshake'] = array( //ROOT menu
        'title' => 'Milkshake flavors',
        'type' => MENU_NORMAL_ITEM, //MENU_CALLBACK,
        'page callback' => 'milkshake_overview',
    );
    $items['milkshake/list'] = array(
        'title' => 'List DEFAULT TASK',
        'type' => MENU_DEFAULT_LOCAL_TASK,//此型態 page callback 參數是無效的
        //'page callback' => 'milkshake_overview', //無效的等同 parent menu
        'weight' => 0,
    );
        $items['milkshake/list/fruity'] = array(
            'title' => 'Fruity TASK',
            'type' => MENU_LOCAL_TASK,
            'page callback' => 'milkshake_list',
            'page arguments' => array(2),
        );
        $items['milkshake/list/Candy'] = array(
            'title' => 'Candy TASK',
            'type' => MENU_LOCAL_TASK,
            'page callback' => 'milkshake_list',
            'page arguments' => array(2),
        );
            $items['milkshake/list/Candy/Candy1'] = array(
                'title' => 'Candy1 ACTION',
                'type' => MENU_LOCAL_ACTION,
                'page callback' => 'milkshake_list',
                'page arguments' => array(3),
            );
            $items['milkshake/list/Candy/Candy2'] = array(
                'title' => 'Candy2 ACTION',
                'type' => MENU_LOCAL_ACTION,
                'page callback' => 'milkshake_list',
                'page arguments' => array(3),
            );
    $items['milkshake/add'] = array(
        'title' => 'Add TASK',
        'type' => MENU_LOCAL_TASK,
        'page callback' => 'milkshake_add',
        'weight' => 1,
    );
        $items['milkshake/add/a1'] = array(
            'title' => 'a1 TASK',
            'type' => MENU_LOCAL_ACTION,
            'page callback' => 'milkshake_add',
        );
        $items['milkshake/add/a2'] = array(
            'title' => 'a2 TASK',
            'type' => MENU_LOCAL_ACTION,
            'page callback' => 'milkshake_add',
        );
    return $items;
}
 
function milkshake_overview() {    return = t('The following flavors are available...');   }
function milkshake_add() {    return t('A handy form to add flavors might go here...');   }
function milkshake_list($type) {    return t('List @type flavors', array('@type' => $type));   }
使用注意
  • Root Menu 必須為 MENU_NORMAL_ITEM, 或 MENU_CALLBACK
  • 同一層級僅有一個 _TASK item 時不會顯示, 單一item 採用 MENU_LOCAL_ACTION
  • _TASK item 最多僅顯示到第二層級, 以後均不會顯示
  • _ACTION 為單層次, 均會在頁面顯示下一層, 深度無限制
  • _ACTION 若在第二層以後, 當點選時若 root 層為 _TASK, 其tab選單將不在繼續顯示
  • _ACTION 若在第一層, 當點選時若 root 層為 _TASK, 其tab選單仍會繼續顯示
Free Web Hosting