Как использовать hook_menu_alter () для управления доступом к пути - PullRequest
3 голосов
/ 26 февраля 2011
/**
 * 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']);
  }
}

Вышеприведенная функция из про разработки drupal. Я не могу понять это хорошо. Почему я должен сбросить аргументы доступа (unset($callbacks['node/add/joke']['access arguments']);)?

Спасибо.

Ответы [ 2 ]

19 голосов
/ 26 февраля 2011

Весь этот пример кажется сломанным и плохим.Короче шутка.Сначала позвольте мне ответить на ваш вопрос, затем я объясню, почему вы не должны следовать этому примеру на практике.

С включает в себя / 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');
}

Теперь у нас есть функция, которая берет путь узла / добавления / шутки и объявляет, что only имеет значение, имеет ли пользователь разрешение 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(), поскольку он почти наверняка был бы более производительным, чем то, что происходит в исходном обратном вызове доступа.

2 голосов
/ 26 февраля 2011

Комментарий прямо над этой строкой объясняет это?

обратный вызов доступа - это функция, которая вызывается (или ИСТИНА / ЛОЖЬ), а аргументы - это то, что передается этой функции.Вы устанавливаете обратный вызов на false и поэтому всегда запрещаете доступ к этому элементу маршрутизатора.

И теперь, как говорится в комментарии, вам также нужно сбросить аргументы, иначе Drupal будет по-прежнему использовать user_access ()обратный вызов).

...