страница предварительной обработки крючка: "загрузка узла() + просмотр страницы узла()" по сравнению с "%узел + просмотр страницы узла()"
Существует базовый узел (nid "123"), и модуль зарегистрировал два пути, используя hook_menu
:
first/%node
second
Оба обратных вызова страницы используют node_page_view($node)
для отображения полностраничного представления узла, за исключением того, что второй обратный вызов дополнительно использует node_load(123)
для получения ссылки на $node
.
Поэтому http://localhost/first/123
и http://localhost/second
выглядят одинаково, насколько это касается пользователя.
Однако hook_preprocess_page
получает переменную node
только с первый путь, поэтому Drupal, очевидно, делает что-то помимо node_load
, когда он видит подстановочный знак %node
, любая идея, что это такое, чтобы hook_preprocess_page
получал ссылку на $node
в обоих случаях ? (потому что внутренняя обработка всего во втором пути создает гораздо более удобные URL-адреса, чем перенаправление на первый путь со второго).
Пример:
<?php
/**
* Implementation of hook_preprocess_page().
*/
function mymodule_preprocess_page(&$vars){
if (@isset($vars['node'])) echo '<h1>[mymodule.module] Node is defined</h1>';
else echo '<h1>[mymodule.module] Node is NOT defined</h1>';
}
/**
* Implementation of hook_menu().
*/
function mymodule_menu(){
return array(
'first/%node' => array(
'title' => 'First callback',
'page callback' => 'mymodule_page_first',
'page arguments' => array(1),
'access callback' => TRUE,
),
'second' => array(
'title' => 'Second callback',
'page callback' => 'mymodule_page_second',
'access callback' => TRUE,
),
);
}
/**
* Page callback for url "http://localhost/first/123".
*/
function mymodule_page_first($node){
echo '<h1>[mymodule.module] Function mymodule_page_first</h1><pre>';
var_dump($node);
echo '</pre>';
return node_page_view($node);
}
/**
* Page callback for url "http://localhost/second".
*/
function mymodule_page_second(){
$node = node_load(123); //the ID of an existing node
echo '<h1>[mymodule.module] Function mymodule_page_second</h1><pre>';
var_dump($node);
echo '</pre>';
return node_page_view($node);
}
(Источник файла mymodule.module
)
Моя лучшая/единственная надежда на данный момент - это покопаться в источнике node_page_view
и все функции, которые он, следовательно, запускает, пока я не найду, что происходит между моментом вызова node_page_view
и моментом вызова module_invoke_all
, который запускает крючок.
2 answers
Когда mymodule_preprocess_page()
вызывается для пути "первый/%узел", он получает объект узла, потому что путь связан с узлом из модуля.
Drupal не может связать объект узла с путем, таким как "/admin/содержимое/узел" (путь Drupal 6), потому что путь не содержит ссылки на идентификатор узла, который помечен как идентификатор узла. Какой объект узла должен возвращать Drupal для таких путей, учитывая, что веб-сайт Drupal может содержать сотни узлов?
Ваш вопрос: "как может Drupal связать объект узла в одном случае, но не в другом?"
Ответ содержится в коде template_preprocess_page(), который функция выполнила перед шаблоном page.tpl.php визуализируется.
В этой функции вы найдете следующий код:
if ($node = menu_get_object()) {
$variables['node'] = $node;
}
Параметры по умолчанию для menu_get_object() являются $type = 'node', $position = 1, $path = NULL
, что означает, что template_preprocess_page()
запрашивает объект узла, связанный с заполнителем в позиции #1, который является возвращаемым значением, например, из arg(1)
.
Взглянув на источник menu_get_object()
, вы заметите, что выполняемый код выглядит следующим образом:
function menu_get_object($type = 'node', $position = 1, $path = NULL) {
$router_item = menu_get_item($path);
if (isset($router_item['load_functions'][$position]) && !empty($router_item['map'][$position]) && $router_item['load_functions'][$position] == $type . '_load') {
return $router_item['map'][$position];
}
}
Используя аргументы по умолчанию, функция проверит, что функция загрузки, связанная с пунктом маршрута № 1, является node_load()
. Если функция загрузки такова, то она вернет значение, возвращенное функцией загрузки вызывающей функции (в нашем случае, template_preprocess_node()
).
Чтобы автоматически получить объект узла, ваш обратный вызов меню должен использовать путь, такой как "второй/%узел" (который был бы совместим с аргументами по умолчанию menu_get_object()
). Единственная проблема заключается в том, что для таких путей необходимо передать идентификатор узла; если URL-адрес http://example.com/second , Drupal покажет страницу с ошибкой 404, так как заполнитель требует параметра, который необходимо передать.
Чтобы решить эту проблему, модуль должен определить два обратных вызова меню: один, связанный со "вторым", и один, связанный с "вторым/%узлом". При первом обратном вызове меню узел не будет получен объект, в то время как второй получит объект узла (и mymodule_preprocess_page()
тоже получит его).
В качестве альтернативы вам следует изменить код mymodule_preprocess_page()
на что-то похожее на:
/**
* Implementation of hook_preprocess_page().
*/
function mymodule_preprocess_page(&$vars){
// Check if the page being served is one of the pages handled by the module.
if (arg(0) == 'first' || arg(0) == 'second') {
if (isset($vars['node'])) {
// The page is a node page.
}
else {
$vars['node'] = mymodule_load_the_default_node();
}
// …
}
}
Когда Drupal видит подстановочный знак "%узел" в URL-адресе, он знает, что аргумент ссылается на идентификатор узла, поэтому автоматически устанавливает для вас переменную $node
, делая ее доступной в hook_preprocess_page
. В вашем "втором" обратном вызове меню вы должны установить переменную $vars['node']
. Таким образом, вы можете использовать его hook_preprocess_page
.
Ссылка: http://drupal.org/node/224170