Как запускать код при каждом запросе страницы - после загрузки модулей?
Я хочу написать модуль, который перенаправляет посетителей на другую страницу на основе модуля geoip.
Существует функция hook_boot(), которая выполняется при всех запросах страниц, но до загрузки модулей. Существует также hook_init(), который не запускается на кэшированных страницах. Мне нужно что-то, что запускается после загрузки всех модулей, но до того, как будут обработаны кэшированные страницы. Я пропустил еще один крючок в документации?
Примечание: Отключение кэша не является опция по соображениям производительности.
5 answers
Я думаю, что лучше всего обобщить варианты в новом ответе:
Во-первых: Нет крючка, который выполняется между hook_boot()
и hook_init()
. Это означает, что нет крючка, который имеет полностью инициализированную среду drupal и выполняется независимо от кэша страниц. -- спасибо @kiamlaluno за то, что прояснил это.
Есть еще два способа получить аналогичный эффект:
- Можно выборочно загружать включаемые файлы или модули в
hook_boot()
с помощью module_load_include() или drupal_load() соответственно. Это особенно полезно, если вам нужна только некоторая довольно автономная функциональность, которая не распространяется на большое количество файлов. - Модуль dynamic_cache можно использовать для динамической деактивации кэша при определенных загрузках страниц, установив
$GLOBALS['conf']['cache'] = FALSE
вhook_boot()
, а затем выполнив тяжелую работу вhook_init()
. - благодаря @David Meister
Эти два метода также могут быть объединены, чтобы сузить число запросы, в которых необходимо отключить кэширование: Используйте минимальную начальную загрузку в hook_boot()
, чтобы точно определить, когда необходимо отключить кэширование.
Однако модуль dynamic_cache кажется довольно хакерским. Так что пока я буду придерживаться метода 1.
Мне нужно что-то, что запускается после загрузки всех модулей, но до того, как будут обработаны кэшированные страницы.
Вы не можете, так как загрузка всех модулей является последней фазой начальной загрузки Drupal, в то время как кэшированные страницы обслуживаются на втором этапе начальной загрузки.
Смотрите код, используемый drupal_bootstrap().
switch ($current_phase) {
case DRUPAL_BOOTSTRAP_CONFIGURATION:
_drupal_bootstrap_configuration();
break;
case DRUPAL_BOOTSTRAP_PAGE_CACHE:
_drupal_bootstrap_page_cache();
break;
case DRUPAL_BOOTSTRAP_DATABASE:
_drupal_bootstrap_database();
break;
case DRUPAL_BOOTSTRAP_VARIABLES:
_drupal_bootstrap_variables();
break;
case DRUPAL_BOOTSTRAP_SESSION:
require_once DRUPAL_ROOT . '/' . variable_get('session_inc', 'includes/session.inc');
drupal_session_initialize();
break;
case DRUPAL_BOOTSTRAP_PAGE_HEADER:
_drupal_bootstrap_page_header();
break;
case DRUPAL_BOOTSTRAP_LANGUAGE:
drupal_language_initialize();
break;
case DRUPAL_BOOTSTRAP_FULL:
require_once DRUPAL_ROOT . '/includes/common.inc';
_drupal_bootstrap_full();
break;
}
Если вы посмотрите на _drupal_bootstrap_page_cache(), вы заметите, что hook_boot()
в конечном итоге вызывается до того, как страница будет отправлена из кэшированные данные, в то время как hook_exit()
в конечном итоге вызывается после того, как страница будет обработана из кэшированных данных. Эти крючки вызываются, если значение переменной Drupal "page_cache_invoke_hooks" равно TRUE
.
if (variable_get('page_cache_invoke_hooks', TRUE)) {
bootstrap_invoke_all('boot');
}
drupal_serve_page_from_cache($cache);
// If the skipping of the bootstrap hooks is not enforced, call
// hook_exit.
if (variable_get('page_cache_invoke_hooks', TRUE)) {
bootstrap_invoke_all('exit');
}
Обратите внимание, что в Drupal 8, hook_boot()
был удален и , так же как и hook_exit()
. Это означает, что Drupal 8 никогда не будет вызывать эти крючки.
Я знаю, что вы сказали, что отключение кэша не является опцией, но модуль динамического кэша позволяет отключать кэш условно в hook_boot, что на самом деле может быть опцией, так как кэш будет отключен только для пользователей, которых вы собираетесь перенаправить - http://drupal.org/project/dynamic_cache
Если вы можете извлечь необходимую логику из GeoIP в hook_boot(), то вы можете отключить кэш для загрузки этой страницы и просто выполнить drupal_goto() в hook_init().
Или вы можете просто загрузить модули в hook_boot()
, тогда drupal не придется загружать их позже, и вы сможете делать с модулями все, что захотите. Я понимаю, что это немного нерегулярно, но программирование на Drupal, похоже, требует нескольких нерегулярных способов выполнения задач.
Вы можете попробовать hook_exit, который запускается даже на кэшированных страницах. Я не уверен, работает ли drupal_goto внутри него, но если это не так, вы могли бы сделать то, что делает модуль boost, и использовать header('Location: mynewurl')
.