Хочу поделиться способом решения одной задачи для сборки Drupal Commons. По требованиям ТЗ нужно было ограничить доступ пользователей к нодам по определенным правилам:
Сразу я пытался реализовать это через
И пошел другим путем.
Вспомним про реестр меню. Массив с описанием элемента содержит в себе два параметра:
Спасибо Anonym за исправления.
Стоит отметить, что при установке модуля я выставляю его вес очень большим (т.е. мой модуль будет выполняться в последнюю очередь и никто больше не переопределит меню). Если у вас иная ситуация — лучше добавить свои параметры в массив, например:
Но в этом случае, не будут учитываться более поздние альтеры. Т.е. все-таки лучше устанавливать вес модуля большим.
Теперь сам callback:
Для меня это сработало и показалось достаточно удобным, возможно пригодится еще кому-либо.
- Пользователи с определенной ролью могут видеть только определенный тип групп
- Эти пользователи могут видеть только контент группы, где они состоят
Сразу я пытался реализовать это через
hook_node_grants и hook_node_access_records, но пришел к выводу, что решение получается слишком громоздкое, глючное и замусоренное.И пошел другим путем.
Вспомним про реестр меню. Массив с описанием элемента содержит в себе два параметра:
access callback и access arguments. Попробуем переопределить их, но сохраним установленный access callback, как последний элемент в access arguments://Хук MYMODULE_menu_alter будет вызываться только при очистке кэша системы function MYMODULE_menu_alter(&$items) { foreach ($items as &$item) { if (!isset($item['access arguments'])) { $item['access arguments'] = array(); } if (isset($item['access callback'])) { //Сохраним стандартный callback, чтобы учитывать и его. $item['access arguments'][] = $item['access callback']; } else { //Если callback не установлен, но присутствуют аргументы, Drupal 6 //использует стандартный user_access() if (!empty($item['access arguments'])) { $item['access arguments'][] = 'user_access'; } else { //Если параметры не установлены вообще - значит по-умолчанию доступ есть $item['access arguments'][] = TRUE; } } //Устанавливаем наш callback $item['access callback'] = 'MYMODULE_access_callback'; } }
Спасибо Anonym за исправления.
Стоит отметить, что при установке модуля я выставляю его вес очень большим (т.е. мой модуль будет выполняться в последнюю очередь и никто больше не переопределит меню). Если у вас иная ситуация — лучше добавить свои параметры в массив, например:
$item['default access callback'] = $item['access callback'];
Но в этом случае, не будут учитываться более поздние альтеры. Т.е. все-таки лучше устанавливать вес модуля большим.
Теперь сам callback:
function MYMODULE_access_callback() { $args = func_get_args(); //Если параметр один, здесь может быть только TRUE, FALSE или коллбэк без аргументов //Нас не интересует, оставляем как есть if (count($args) == 1) { if (is_bool($args[0])) { return $args[0]; } return $args[0](); } //Вытащим callback по-умолчанию и его параметры $callback = $args[count($args) - 1]; $callback_args = array_slice($args, 0, count($args) - 1); //Права доступа к нодам: if (is_object($args[1]) && isset($args[1]->nid)) { //Для начала проверим стандартные права //если доступа нет, то и наши проверять не имеет смысла if (!call_user_func_array($callback, $callback_args)) { return FALSE; } //Если 3-й аргумент так-же объект, то это аккаунт //т.к. node_access($op, $node, $account = NULL) if (is_object($args[2])) { $account = $args[2]; } else { global $user; $account = $user; } //Теперь проверяем права сами: if ($condition && some_rights()) { return TRUE; } else { return FALSE; } } //На всякий случай if (!function_exists($callback)) { $dump = print_r($callback_args, TRUE); $msg = ' <b>Access callback не существует!</b><br /> Callback: "%callback"<br /> Callback arguments:<hr> <pre> %args </pre> '; $vars = array( '%callback' => $callback, '%args' => $callback_args ); watchdog('php', $msg, $vars, WATCHDOG_ERROR); return TRUE; } //Просто используем стандартный коллбэк return call_user_func_array($callback, $callback_args); }
Для меня это сработало и показалось достаточно удобным, возможно пригодится еще кому-либо.
