1. Колбек маппинг.
2. Контроль доступа.
3. Кастомизация.
Ядро системы живет в /include/menu.inc, а опциональная часть (такая как кастомизация) в modules-menu.
Задачей системы меню является диспетчеризация (или роутинг), это еще один синоним первого кита "коллбек маппинга". В таблице menu_router храняться пути сайта и имена функций, которые обрабатывают каждый конкретный путь, а также параметры для передачи в эти функции. В таблице menu_link хранятся айтемы менюшек(которые присутсвуют на сайте) связанные с путями в menu_router.
Когда на сайт приходит запрос, он обрабатывается по следующим шагам:
1. Обрабатывается путь, если это алиас, то он трансформируется в оригинальный.
2. Смотрит в menu_links, какие меню нужно сформировать на сайте. Формирует массивы меню. Проверяет не нужно ли обновить эту и menu_router таблицы.
3. Смотрит в menu_router, какой колбек привязан на запрошенный путь.
4. Загружает обьекты, которые необходимые для передачи в колбек.
5. Проверяет можно ли вызывать этот колбек(ити по запрошенному пути) для поточного юзера.
6. Локализирует массивы с менюшками.
7. Загружает необходимые инклюд файлы.
8. Вызывает колбек. А результат в индексе пропускается через theme_page().
Меню Navigation формируется вызовом хуков hook_menu из подключенных модулей. Так каждый модуль имеет возможность добавить в административное меню собственный пункт.
Хук должен вернуть массив следующей структуры:
function MODULENAME_menu() {
$items['path_in_nav'] = array(
'title' => 'Титул',
'page callback' => 'имя_колбека',
'page arguments' => array('параметр1', 'параметр2'),
'access callback' => 'имя_функции проверяющей_доступ',
'access arguments' => array('необходимый_пермишин'),
'file' => 'имя_файла.inc',
'file path' => 'путь к файлу'
'type' => MENU_CALLBACK,
'weight' => 5
);
return $items;
}
page arguments - эти параметры идут первыми в параметры 'имя_колбека', сразу за ними поступают параметры с урла (http://example.com/path_in_nav/param3/param4).file - в файлы модулей размещаются только хуки, чтобы не загружать в память код, который возможно и не понадобится для обработки текущего запроса. А дополнительные функции живут в файлах 'имя_файла.inc'. Перед вызовом колбека сначала заинклюдится этот файл.file path - если передыдущий файл не находится в модуле который определяет хук_меню, то нужно указать и путь к нему.type - в данном случае у нас тип MENU_CALLBACK, что означает нужно обеспечить только обработку данного запроса нужным колбеком, но при этом в меню не появится такого айтема. А если мы поставим тип MENU_NORMAL_ITEM, или просто его упустим(по умолчании тип именно MENU_NORMAL_ITEM), то наш айтем появится в административном меню. weight - порядок элемента в меню.access callback- это булиновская функция проверки доступа, если ее не указывать, то по-умолчанию вызывается user_access().access arguments- это параметры для передачи в ексес колбек. Если ексес колбек user_access, то в аргменты можно передавать массив с необходимыми пермишинами, и для каждого елемента массива вызывается user_access, а их результаты слаживаются в логическое "и".Модуль может опеределять свои собственные пермишины через хук MODULENAME_perm
function MODULENAME_perm() {
return array('необходимый пермишин');
}
Вложенность меню
Чтобы создать вложенное меню нужно просто указать через слеш в массиве ключ:
function MODULENAME_menu() {
$items['path_in_nav'] = array(
'title' => 'Титул',
'page callback' => 'имя_колбека',
'page arguments' => array('параметр1', 'параметр2'),
'access callback' => 'имя_функции проверяющей_доступ',
'access arguments' => array('необходимый_пермишин'),
'file' => 'имя_файла.inc',
'file path' => 'путь к файлу'
'type' => MENU_CALLBACK,
'weight' => 5
);
$items['path_in_nav/its_subpath'] = array(
...
);
return $items;
}
При этом нужно помнить, что вложенные меню не наследуют от родителей 'access callback' и 'access arguments'. Исключением только является меню айтем типа MENU_DEFAULT_LOCAL_TASK, такое меню наследует отцовские ексес колбек и ексес аргументы.
Локализация и катомизация
Тайтлы и дескрипшины меню не нужно пропускать через функцию локализации t(), потому что это происходит в системе меню:
'title' => t('Greeting') // No! don't use t() in menu item titles or descriptions.
К тому же функцию, которую использует система меню, для преобработки тайтла можно заменить (но этого нельзя сделать для дескрипшина):
'title callback' => 't', // это можно и не писать, потому что t() по-умолчанию
В функции локализации можно применять параметры:
t($string, $keyed_array);
t('It is now @time', array('@time' => $now));
В дополнение к 'title callback' эсть еще 'title arguments', кстати если параметры числа, то их обязательно нужно окружать литералами, числа имеют специальное значение:
function MODULENAME_menu() {
$items['path'] = array(
'title' => 'Greeting for Dr. @name',
'title callback' => 't',
'title arguments' => array('@name' => 'Foo'),
'page callback' => 'callback_name',
'access callback' => TRUE,
);
return $items;
}
Но нужно помнить, что в этом случае аргументы сохраняются в базу только в момент создания меню, и если у нас 'title arguments' вставляются результаты функции, то это будет отработка функции только в момент создания меню, а дальше мы увидим кеш... Да каждый раз будет вызываться функция t(), но вот параметры будут браться из кеша.Чтобы параметр был динамическим нужно переопределить 'title callback', и внутри его вызывать t() c динамическими параметрами:
function menufun_menu() {
$items['menufun'] = array(
'title' => 'Greeting',
'title callback' => 'menufun_title',
'description' => 'A salutation.',
'page callback' => 'menufun_hello',
'access callback' => TRUE,
);
return $items;
}
/**
* Page callback.
*/
function menufun_hello() {
return t('Hello!');
}
/**
* Title
*/
function menufun_title() {
$now = format_date(time());
return t('It is now @time', array('@time' => $now));
}Чтобы применились изменения в хуке меню, нужно не просто зайти на страницу admin/build/modules, а и нажать на кнопку сейв.
Ваилдкарды в меню айтемах
Мы можем путь определять с ваилдкардом внутри. Такой путь не может быть элементом меню, поэтому это тоже самое, что айтем с типом MENU_CALLBACK, при этом этот самый тип мы можем ставить какой угодно, все равно в меню ничего не появится. Ваилдкард разбивает паз на части, например:
$items['menufun/%'] = array(...);К этому пути подходит menufun/foo, menufun/foom/baz, но не menufun. При этом во втором пути 'baz' пойдет как пазовый параметр в колбековую функцию, это потому что ваилдкард разбивает путь на две части, а части определяет слеш.
Теперь поподробнее о разбивке мы столконемся в параметрах для колбека:
$items['menufun/%/bar/baz'] = array( ... 'page arguments' => array(1), );Это означает, что если мы придем по пути menufun/foo/bar/baz/Fred, то в колбек первым параметром пойдет foo, как вторая часть паза(под индексом 1), которая передается через 'page arguments', а вторым параметром - Fred, как пазовый параметр. При этом мы в колбек можем передать все части паза, которые разбиваются на 4 части под воздействием ваилдкарда. Таким образом мы можем передать все части паза в переменные колбека:
$items['menufun/%/bar/baz'] = array( ... 'page arguments' => array(0,1,2,3), );Колбек получит следующие перменные callback('menufun','anithing from path','bar','baz','Fred'), при этому первые четыре из-за 'page arguments' => array(0,1,2,3), а последний как пазовый параметр.
Ваилдкарды и замещение параметров
Как уже было выше сказано, мы разбиваем путь на части по слешу. А что означает, если после % будет идти не следующий слеш, а символы? Это означает то, что вместе этой части паза будет идти не то, что подошло под ваилдкард, а результат функции в которую передалась как параметр эта часть паза. Какая именно функция вызывается станет понятно с примера:
$items['user/%user_uid_optional'] = array( 'title' => 'My account', 'title callback' => 'user_page_title', 'title arguments' => array(1), 'page callback' => 'user_view', 'page arguments' => array(1), 'access callback' => 'user_view_access', 'access arguments' => array(1), 'file' => 'user_pages.inc', );К примеру на сервер пришел запрос http://example.com/?q=user/2375. Это означает что функции 'user_page_title', 'user_view' и 'user_view_access' получат аргументом не значение 2375, а обект юзера, который вернет функция user_uid_optional_load(2375). С примера стало понятно, что имя функции формируется по следующему правилу: 'то что после %' + '_load'.
Передача дополнительных параметров в функции загрузки
Иногда необходимо в функцию загрузки передать дополнительный параметр:
$items['node/%node/revisions/%/view'] = array( 'title' => 'Revisions', 'load arguments' => array(3), 'page callback' => 'node_show', 'page arguments' => array(1, NULL, TRUE), 'type' => MENU_CALLBACK, );Если к примеру на сервер пришел запрос
http://example.com/?q=node/56/revisions/4/view. То функция node_show, получит параметры node_show(node_load(56,4), NULL, TRUE). Но на самом деле не все так просто, в функции загрузчики всегда еще передается дополнительно два парметра _load(....,$map, $index), где мап это паз в виде массива, а индекс позиция в этом масиве с которой вызывается данный лоад. И поэтому на самом деле функция будет вызываться так: node_show(node_load(56,4), NULL, TRUE, array('node','56','revisions','4','view'), 1).Кстати именно благодаря предоперделенному параметру $map, мы можем изменить паз, для дальнейших функций загрузки, которые идут за поточной. Достаточно в определении функции указать параметр мапа как ссылка, пример из ядра друпала:
function user_category_load($uid, &$map, $index) {
...
}
Хотя я выше и писал, что ваидкарды не могут быть в меню навигация, на самом деле это не так. Ведь как тогда формируется пункт меню 'My account' со ссылку на профайл залогиненного поточного юзера? Все дело в том, что действительно, если ваилдкард без имени ('../%/..'), то мы действительно не сможем никак его разместить в меню, но если имя есть. То Drupal ищет функцию 'имя_ваидкарда_to_arg($arg)'. Мы можем делать некие исчисления внутри этой функции и возвращать динамеческую ссылку в меню. Парметр $arg обыно содержит '%', но если мы перейдем по ссылке на которую указывает наш динамический пункт меню, то наша имя_ваидкарда_to_arg вызовется несколько раз (пока незнаю почему), и после первого раза будет передаваться результат предыдущей отработки этой функции. Мы можем проверять равняется ли аргумент '%', если нет то не перещитывать повторно значаени ссылки.
Изменение существующих меню айтемов из других модулей
Для этого есть хук:
function MODULENAME_menu_later(&$items) {
$items['path/to/item']['page callback'] = 'new_callback';
$items['path/to/item']['access callback'] = 'new_callback2';
//etc
}
Есть еще один хук с помошью которого меняются линки в менюшках(тайтлы или вес), но не колбеки:
function MODULENAME_link_alter(&$item, $menu) {
if ($item['link_path'] == 'logout') {
$item['link_title'] = 'Sign off';
}
}
Этот хук вызывается под каждый айтем, при этом $menu это общий набор айтемов в иерархичной структуре
Типы меню айтемов
Это флаги, которые определяют, что делать с определенным роутом. Показывать в меню/не показывать и т.д. Это битовые маски, которые могут складываться:

Комментариев нет:
Отправить комментарий