2011-02-26 77 views
3
/** 
* Implementation of hook_menu_alter(). 
*/ 
function joke_menu_alter(&$callbacks) { 
    // If the user does not have 'administer nodes' permission, 
    // disable the joke menu item by setting its access callback to FALSE. 
    if (!user_access('administer nodes')) { 
    $callbacks['node/add/joke']['access callback'] = FALSE; 
    // Must unset access arguments or Drupal will use user_access() 
    // as a default access callback. 
    unset($callbacks['node/add/joke']['access arguments']); 
    } 
} 

上面的函數是從pro開發的drupal。我無法理解。爲什麼我必須取消訪問參數(unset($callbacks['node/add/joke']['access arguments']);)如何使用hook_menu_alter()來操作路徑訪問控制

謝謝。

回答

19

整個例子似乎壞了。總之,一個笑話。首先,讓我回答你的問題,然後我會繼續解釋爲什麼你不應該在實踐中遵循這個例子。

包括/ menu.inc

if (!isset($item['access callback']) && isset($item['access arguments'])) { 
    // Default callback. 
    $item['access callback'] = 'user_access'; 
} 

解封訪問回調,當你不再需要他們(靠一個布爾值,畢竟現在)防止過度聰明的邏輯Drupal的路由系統從拍打user_access()只是所以它有事情要做。

現在,爲什麼這是錯誤的代碼。

hook_menu()hook_menu_alter()都運行在高速緩存清除(更具體地說,當菜單路由系統被重建時)。這意味着無論用戶點擊網站來重建菜單的權限都將被硬編碼爲菜單路由行爲。這是一個非常糟糕和不一致的安排。

如果您想要根據權限阻止訪問路徑,則需要將回調更改爲將測試該權限的內容。然後當菜單重建時,它將檢查每頁加載的新回調函數,以查看是否應該授予當前用戶權限。

的一個簡單的例子可能是:

/** 
* Implementation of hook_menu_alter(). 
*/ 
function joke_menu_alter(&$items) { 
    $items['node/add/joke']['access callback'] = 'user_access'; 
    $items['node/add/joke']['access arguments'] = array('administer nodes'); 
} 

現在我們有一個函數,使用節點/添加/笑話路徑並宣佈事情,重要的是,是否用戶有administer nodes權限。當然,這比示例的明顯意圖稍微有點侷限,這些示例旨在保留現有的訪問控制,但也要求用戶擁有administer nodes權限。

這也是可以修復的,但更復雜。借用一些概念從Spaces項目:

/** 
* Implementation of hook_menu_alter(). 
*/ 
function joke_menu_alter(&$items) { 
    $path = 'node/add/joke'; 
    $items[$path]['access arguments'][] = $items[$path]['access callback']; 
    $items[$path]['access callback'] = 'joke_menu_access'; 
} 

function joke_menu_access() { 
    $args = func_get_args(); 
    $access_callback = array_pop($args); 
    $original_access = call_user_func_array($access_callback, $args); 
    return $original_access && user_access('administer nodes'); 
} 

我們已經成功地包裹原始訪問回調新的接入回調,這是我們可以添加我們需要的任何額外的邏輯。

請注意,在最後兩個函數示例中,我使用了$path變量來使代碼簡單。我也將$original_access分隔到自己的行,並先檢查它,實際上我會首先檢查user_access(),因爲它幾乎可以肯定比原始訪問回調中發生的任何事情都更有效。

+1

我只是想增加一個謝謝,即使投票後,不僅告訴OP如何,但爲什麼*!哦,我希望有一個加10當答案深入。 – Richard 2013-09-04 14:45:26

2

直接在該行上面的註釋解釋它?

訪問回調是被調用的函數(或TRUE/FALSE),參數是傳遞給該函數的函數。您將回調設置爲false,因此始終拒絕對該路由器項目的訪問。

現在,正如評論所說,您還需要取消設置參數,否則Drupal仍將使用user_access()(默認訪問回調)。